copilot-operator 0.1.20 → 0.1.22
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/dist/src/api/operator.controller.js +49 -0
- package/dist/src/api/operator.service.js +179 -7
- package/dist/src/orchestrator/taskRunner.js +14 -2
- package/dist/src/plan/systemGuide.js +119 -15
- package/dist/src/session/exports.js +70 -1
- package/dist/src/session/runLog.js +60 -0
- package/dist/src/vcs/git.js +11 -1
- package/dist/src/vcs/inputs.js +26 -2
- package/dist/src/vcs/prepareFromRemote.js +263 -0
- package/dist/src/vcs/runPreflight.js +286 -0
- package/dist/src/vcs/taskVcs.js +42 -6
- package/dist/web/404.html +2 -2
- package/dist/web/_next/static/chunks/549-5f90780046c1c24f.js +1 -0
- package/dist/web/_next/static/chunks/867-79f07bebe3084811.js +1 -0
- package/dist/web/_next/static/chunks/app/defaults/page-cdc730adea753446.js +1 -0
- package/dist/web/_next/static/chunks/app/page-0a861b38da0a1c51.js +1 -0
- package/dist/web/_next/static/chunks/app/sessions/view/page-185755ada66e2930.js +1 -0
- package/dist/web/appearance.html +2 -2
- package/dist/web/appearance.txt +10 -10
- package/dist/web/defaults.html +2 -2
- package/dist/web/defaults.txt +10 -10
- package/dist/web/history.html +2 -2
- package/dist/web/history.txt +10 -10
- package/dist/web/import.html +2 -2
- package/dist/web/import.txt +10 -10
- package/dist/web/index.html +2 -2
- package/dist/web/index.txt +10 -10
- package/dist/web/level1.html +2 -2
- package/dist/web/level1.txt +10 -10
- package/dist/web/presets.html +2 -2
- package/dist/web/presets.txt +10 -10
- package/dist/web/sessions/view.html +2 -2
- package/dist/web/sessions/view.txt +10 -10
- package/dist/web/system.html +2 -2
- package/dist/web/system.txt +10 -10
- package/package.json +150 -148
- package/dist/web/_next/static/chunks/549-5d7c845fb0a27dbe.js +0 -1
- package/dist/web/_next/static/chunks/867-d9c54f7a2b285b3f.js +0 -1
- package/dist/web/_next/static/chunks/app/defaults/page-fd819bbfa7f33982.js +0 -1
- package/dist/web/_next/static/chunks/app/page-409e37e208dc12e5.js +0 -1
- package/dist/web/_next/static/chunks/app/sessions/view/page-99f9153fd75078d0.js +0 -1
- /package/dist/web/_next/static/{P0lpNIJvdSO3yuWRpIPQf → 9Ze8aagkvT-WLfD4KCKKS}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{P0lpNIJvdSO3yuWRpIPQf → 9Ze8aagkvT-WLfD4KCKKS}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version control for a run, made ready on the run screen before anything opens the browser.
|
|
3
|
+
*
|
|
4
|
+
* From the feedback of 2026-10-02: the run screen named the right problem once per session, left the
|
|
5
|
+
* run buttons on, and told the operator to approve a list they could not see; and version control was
|
|
6
|
+
* only checked once the browser was open and the first task had begun. Version control should be light
|
|
7
|
+
* and never in the way: every problem comes with the fix, done from here, said exactly before it is
|
|
8
|
+
* done, and nothing about version control is left to find out after the browser opens.
|
|
9
|
+
*
|
|
10
|
+
* So the sessions of a run are grouped by repository — one problem is one problem, however many
|
|
11
|
+
* sessions share the repository — and each group says where it stands (the repository, its branch and
|
|
12
|
+
* HEAD, the base branch the plan asked for and its HEAD, the sessions, the input patterns, the matched
|
|
13
|
+
* files with status and size, the unrelated uncommitted files apart) and what can be done:
|
|
14
|
+
*
|
|
15
|
+
* review-inputs show the input files; changes nothing
|
|
16
|
+
* snapshot-on-base the starting snapshot on the base branch: that branch's tree plus the approved
|
|
17
|
+
* input files only, committed with a temporary index — no branch switched, the
|
|
18
|
+
* operator's checkout untouched. Every session of the run in that repository
|
|
19
|
+
* that starts from that branch starts from it; a chained one carries it on.
|
|
20
|
+
* snapshot-here the starting snapshot where the repository is, as the session page takes it
|
|
21
|
+
* use-current-branch the sessions start from the branch the repository is on instead
|
|
22
|
+
* allow-snapshot uncommitted changes become a starting snapshot to approve, instead of a refusal
|
|
23
|
+
*
|
|
24
|
+
* The run is refused before the browser opens while any group is not ready (see the service).
|
|
25
|
+
*/
|
|
26
|
+
import { join, resolve } from 'node:path';
|
|
27
|
+
import { branchNameFrom, freeBranchName, git } from './git.js';
|
|
28
|
+
import { commitOnto, dirtyBesidesInputs, inputSettings, inputSumsAt, missingInputPatterns } from './inputs.js';
|
|
29
|
+
import { dirtyPolicy, takeSnapshot } from './snapshot.js';
|
|
30
|
+
import { repoDirOf, vcsPreflight } from './taskVcs.js';
|
|
31
|
+
import { artifactPatterns } from './artifacts.js';
|
|
32
|
+
import { inScope } from './scope.js';
|
|
33
|
+
const norm = (dir) => dir.trim().replace(/[\\/]+$/, '').replace(/\//g, '\\').toLowerCase();
|
|
34
|
+
const short = (c) => (c ?? '').slice(0, 8);
|
|
35
|
+
const names = (list) => list.map((s) => `"${s.name}"`).join(', ');
|
|
36
|
+
/** The groups, one per repository, for the sessions of a run in run order. */
|
|
37
|
+
export async function runVcsPreflight(sessions, allSessions) {
|
|
38
|
+
const byRepo = new Map();
|
|
39
|
+
for (const s of sessions) {
|
|
40
|
+
if (!s.vcs?.enabled || !repoDirOf(s))
|
|
41
|
+
continue;
|
|
42
|
+
const key = norm(repoDirOf(s));
|
|
43
|
+
byRepo.set(key, [...(byRepo.get(key) ?? []), s]);
|
|
44
|
+
}
|
|
45
|
+
const groups = [];
|
|
46
|
+
for (const list of byRepo.values())
|
|
47
|
+
groups.push(await groupFor(list, allSessions));
|
|
48
|
+
return groups;
|
|
49
|
+
}
|
|
50
|
+
async function groupFor(list, allSessions) {
|
|
51
|
+
const first = list[0];
|
|
52
|
+
const repoDir = repoDirOf(first);
|
|
53
|
+
const branchR = await git(repoDir, ['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
54
|
+
const headR = await git(repoDir, ['rev-parse', '--verify', '--quiet', 'HEAD']);
|
|
55
|
+
const branch = branchR.ok && branchR.stdout !== 'HEAD' ? branchR.stdout : null;
|
|
56
|
+
const head = headR.ok && headR.stdout ? headR.stdout : null;
|
|
57
|
+
const startFrom = first.vcs?.startFrom ?? 'head';
|
|
58
|
+
const baseBranch = startFrom === 'branch' || startFrom === 'previous-session' ? first.vcs?.baseBranch?.trim() || 'main' : undefined;
|
|
59
|
+
const baseHead = baseBranch ? (await git(repoDir, ['rev-parse', '--verify', '--quiet', `refs/heads/${baseBranch}^{commit}`])).stdout || null : undefined;
|
|
60
|
+
const settings = inputSettings(first.vcs);
|
|
61
|
+
const sessions = list.map((s, i) => {
|
|
62
|
+
const sf = s.vcs?.startFrom ?? 'head';
|
|
63
|
+
const role = i === 0 ? 'first' : sf === 'previous-session' ? 'inherits' : sf === 'branch' && (s.vcs?.baseBranch?.trim() || 'main') === baseBranch && !s.vcsBaseCommit ? 'shares' : 'own';
|
|
64
|
+
return { id: s.id, name: s.name, startFrom: sf, started: !!s.vcsBaseCommit, role };
|
|
65
|
+
});
|
|
66
|
+
const pre = await vcsPreflight(first, allSessions);
|
|
67
|
+
const plan = pre.snapshot;
|
|
68
|
+
const inputs = (plan?.entries ?? []).filter((e) => e.input);
|
|
69
|
+
/*
|
|
70
|
+
* Every uncommitted file that is not an input, read from the tree itself: the snapshot's list stops at
|
|
71
|
+
* the first thing in the way (other changes beside the inputs) and would leave them out.
|
|
72
|
+
*/
|
|
73
|
+
const inputPaths = new Set(inputs.map((e) => e.path));
|
|
74
|
+
const artifacts = artifactPatterns(first.vcs);
|
|
75
|
+
const reasons = new Map((plan?.entries ?? []).filter((e) => !e.input && e.reason).map((e) => [e.path, e.reason]));
|
|
76
|
+
const unrelated = pre.problem === 'off'
|
|
77
|
+
? []
|
|
78
|
+
: (await dirtyBesidesInputs(repoDir, first.vcsStart)).other
|
|
79
|
+
.filter((path) => !inputPaths.has(path) && !(artifacts.length > 0 && inScope(path, artifacts)))
|
|
80
|
+
.map((path) => ({ path, ...(reasons.has(path) ? { reason: reasons.get(path) } : {}) }));
|
|
81
|
+
// Before anything is approved: a pattern that matches nothing is said here, not after the browser opens.
|
|
82
|
+
let problem = pre.ok ? undefined : pre.problem;
|
|
83
|
+
// Problems no approval or setting of version control's own can get past: they need the operator.
|
|
84
|
+
let blocking = false;
|
|
85
|
+
if (!first.vcsBaseCommit && settings) {
|
|
86
|
+
const topR = await git(repoDir, ['rev-parse', '--show-toplevel']);
|
|
87
|
+
const missing = topR.ok ? await missingInputPatterns(first, repoDir, resolve(topR.stdout), allSessions) : [];
|
|
88
|
+
if (missing.length > 0) {
|
|
89
|
+
blocking = true;
|
|
90
|
+
problem = `the input file pattern(s) ${missing.map((m) => `"${m}"`).join(', ')} match no file in the project: put the files in, or correct "Input files" on the session's page.`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/*
|
|
94
|
+
* The branches the sessions name, before the browser opens rather than at their first task: a
|
|
95
|
+
* branch to carry on that is not there, a base branch that is not there.
|
|
96
|
+
*/
|
|
97
|
+
for (const s of list) {
|
|
98
|
+
if (s.vcsBaseCommit)
|
|
99
|
+
continue;
|
|
100
|
+
const named = s.vcs?.startFrom === 'existing-branch' ? s.vcs.existingBranch?.trim() : s.vcs?.startFrom === 'branch' ? s.vcs.baseBranch?.trim() || 'main' : '';
|
|
101
|
+
if (!named)
|
|
102
|
+
continue;
|
|
103
|
+
const there = (await git(repoDir, ['rev-parse', '--verify', '--quiet', `refs/heads/${named}^{commit}`])).stdout;
|
|
104
|
+
if (!there) {
|
|
105
|
+
blocking = true;
|
|
106
|
+
problem = `${problem ? `${problem} ` : ''}"${s.name}" is set to ${s.vcs?.startFrom === 'existing-branch' ? 'carry on' : 'start from'} the local branch "${named}", and there is no such branch: create it, or change "Start from" on the session's page.`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const noCommits = first.vcs?.commitOnFinish === false;
|
|
110
|
+
const ready = blocking ? false : !problem ? true : noCommits && !plan?.needed ? true : !!plan?.needed && plan.ok && !plan.requireApproval;
|
|
111
|
+
const sharing = sessions.filter((s) => s.role === 'first' || s.role === 'shares');
|
|
112
|
+
const inheriting = sessions.filter((s) => s.role === 'inherits');
|
|
113
|
+
const blockedInputs = inputs.filter((e) => e.allowed.length === 0);
|
|
114
|
+
const prefix = first.vcs?.branchPrefix || 'cop/';
|
|
115
|
+
const baselineName = `${branchNameFrom(['baseline'], prefix)}/${first.id}`;
|
|
116
|
+
const actions = [];
|
|
117
|
+
if (inputs.length > 0) {
|
|
118
|
+
actions.push({ id: 'review-inputs', available: true, result: `Shows the ${inputs.length} input file(s) with their git status and size. Changes nothing.` });
|
|
119
|
+
}
|
|
120
|
+
if (baseBranch && !first.vcsBaseCommit && inputs.length > 0) {
|
|
121
|
+
const why = !baseHead
|
|
122
|
+
? `there is no local branch "${baseBranch}"`
|
|
123
|
+
: unrelated.length > 0
|
|
124
|
+
? `besides the input files there are other uncommitted changes (${unrelated.slice(0, 5).map((u) => u.path).join(', ')}${unrelated.length > 5 ? '…' : ''}): commit or stash them first, or use the current branch instead`
|
|
125
|
+
: blockedInputs.length > 0
|
|
126
|
+
? `${blockedInputs.map((b) => b.path).join(', ')} cannot be taken as input files`
|
|
127
|
+
: problem && /match no file/.test(problem)
|
|
128
|
+
? problem
|
|
129
|
+
: undefined;
|
|
130
|
+
actions.push({
|
|
131
|
+
id: 'snapshot-on-base',
|
|
132
|
+
available: !why,
|
|
133
|
+
recommended: !why && branch !== baseBranch,
|
|
134
|
+
...(why ? { why } : {}),
|
|
135
|
+
result: `Commits the ${inputs.length} input file(s) on top of "${baseBranch}" (${short(baseHead)}) as "Capture user-provided inputs", on the new branch ${baselineName}, ` +
|
|
136
|
+
`without switching branches: your checkout${branch ? ` of "${branch}"` : ''} and the files stay exactly as they are. ` +
|
|
137
|
+
`${names(sharing)} start from it${inheriting.length > 0 ? `; ${names(inheriting)} carry it on through the chain` : ''}.`,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (plan?.needed && plan.ok && plan.requireApproval) {
|
|
141
|
+
actions.push({
|
|
142
|
+
id: 'snapshot-here',
|
|
143
|
+
available: true,
|
|
144
|
+
result: plan.recapture
|
|
145
|
+
? `Commits the ${plan.entries.length} changed input file(s) on "${first.name}"'s line of work (${plan.baselineBranch}); the next task starts from them.`
|
|
146
|
+
: `Commits the ${plan.entries.filter((e) => e.choice === 'include').length} file(s) ticked on top of "${branch ?? 'HEAD'}" (${short(head)}) as one commit on the new branch ${plan.baselineBranch}, and puts the repository on it; "${branch ?? 'HEAD'}" itself does not move.` +
|
|
147
|
+
(plan.entries.some((e) => e.choice === 'leave-out') ? ' Files left out go into .git/info/exclude.' : ''),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (baseBranch && startFrom === 'branch' && !first.vcsBaseCommit && branch && branch !== baseBranch) {
|
|
151
|
+
actions.push({
|
|
152
|
+
id: 'use-current-branch',
|
|
153
|
+
available: true,
|
|
154
|
+
result: `${names(sharing)} start from "${branch}" (${short(head)}) instead of "${baseBranch}": their "Start from" becomes "From wherever the repository is". ` +
|
|
155
|
+
'Nothing is committed yet; a snapshot on that branch is offered next if one is needed.',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (!plan?.needed && unrelated.length > 0 && dirtyPolicy(first.vcs).policy === 'reject' && !first.vcsBaseCommit && !noCommits) {
|
|
159
|
+
actions.push({
|
|
160
|
+
id: 'allow-snapshot',
|
|
161
|
+
available: true,
|
|
162
|
+
result: `"Uncommitted changes" for "${first.name}" becomes "Take them as a starting snapshot": the files are listed here for you to approve. Nothing is committed yet.`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
repoDir,
|
|
167
|
+
ready,
|
|
168
|
+
...(problem && !ready ? { problem: problem.replace(/^There are uncommitted changes, and no starting snapshot can be taken: /, '') } : {}),
|
|
169
|
+
branch,
|
|
170
|
+
head,
|
|
171
|
+
...(baseBranch ? { baseBranch, baseHead } : {}),
|
|
172
|
+
sessions,
|
|
173
|
+
inputPatterns: settings?.patterns ?? [],
|
|
174
|
+
inputs,
|
|
175
|
+
unrelated,
|
|
176
|
+
entries: plan?.entries ?? [],
|
|
177
|
+
actions,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Does one action for one repository of a run, after checking it is still what was shown: the group is
|
|
182
|
+
* worked out again, and an action that is no longer available, or a list of files that changed, is
|
|
183
|
+
* refused with nothing done.
|
|
184
|
+
*/
|
|
185
|
+
export async function runVcsPrepare(sessions, repoDir, action, choices, bus, saveSession, allSessions) {
|
|
186
|
+
const list = sessions.filter((s) => s.vcs?.enabled && norm(repoDirOf(s)) === norm(repoDir));
|
|
187
|
+
if (list.length === 0)
|
|
188
|
+
return { ok: false, problem: 'none of the run\'s sessions works in that repository.' };
|
|
189
|
+
const group = await groupFor(list, allSessions);
|
|
190
|
+
const offered = group.actions.find((a) => a.id === action);
|
|
191
|
+
if (!offered || !offered.available)
|
|
192
|
+
return { ok: false, problem: offered?.why ?? 'that is not offered for this repository now. Look again; nothing was done.' };
|
|
193
|
+
const first = list[0];
|
|
194
|
+
if (action === 'review-inputs')
|
|
195
|
+
return { ok: true, result: offered.result };
|
|
196
|
+
if (action === 'use-current-branch') {
|
|
197
|
+
const moved = group.sessions.filter((s) => (s.role === 'first' || s.role === 'shares') && !s.started);
|
|
198
|
+
for (const s of moved) {
|
|
199
|
+
await saveSession(s.id, (x) => {
|
|
200
|
+
if (x.vcs)
|
|
201
|
+
x.vcs.startFrom = 'head';
|
|
202
|
+
x.vcsBaseCommit = undefined;
|
|
203
|
+
x.vcsStart = undefined;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return { ok: true, result: `${names(moved)} now start from "${group.branch}".` };
|
|
207
|
+
}
|
|
208
|
+
if (action === 'allow-snapshot') {
|
|
209
|
+
await saveSession(first.id, (x) => {
|
|
210
|
+
if (x.vcs)
|
|
211
|
+
x.vcs.dirtyWorktree = { policy: 'snapshot' };
|
|
212
|
+
});
|
|
213
|
+
return { ok: true, result: `"${first.name}" takes its uncommitted changes as a starting snapshot once you approve the list.` };
|
|
214
|
+
}
|
|
215
|
+
if (action === 'snapshot-here') {
|
|
216
|
+
const taken = await takeSnapshot(first, { approved: true, choices }, bus, async (m) => saveSession(first.id, m), allSessions);
|
|
217
|
+
return taken.ok ? { ok: true, result: `taken: ${short(taken.start.commit)} on ${taken.start.branch ?? taken.start.inputs?.recaptured?.at(-1)?.branch ?? ''}.` } : { ok: false, problem: taken.problem };
|
|
218
|
+
}
|
|
219
|
+
// snapshot-on-base: the base branch's tree plus the approved inputs only, with a temporary index.
|
|
220
|
+
const paths = group.inputs.map((e) => e.path);
|
|
221
|
+
const shown = Object.keys(choices).sort();
|
|
222
|
+
if (JSON.stringify(shown) !== JSON.stringify([...paths].sort()) || paths.some((p) => choices[p] !== 'include')) {
|
|
223
|
+
return { ok: false, problem: 'the input files changed since the list was shown. Look at the list again; nothing was done.' };
|
|
224
|
+
}
|
|
225
|
+
const topR = await git(repoDir, ['rev-parse', '--show-toplevel']);
|
|
226
|
+
if (!topR.ok || !topR.stdout || !group.baseHead || !group.baseBranch)
|
|
227
|
+
return { ok: false, problem: 'the base branch could not be read.' };
|
|
228
|
+
const top = resolve(topR.stdout);
|
|
229
|
+
const files = [];
|
|
230
|
+
for (const path of paths) {
|
|
231
|
+
const blob = await git(top, ['hash-object', '-w', `--path=${path}`, '--', join(top, path)]);
|
|
232
|
+
if (!blob.ok || !blob.stdout)
|
|
233
|
+
return { ok: false, problem: `${path} could not be read into git: ${blob.stderr}` };
|
|
234
|
+
const mode = (await git(top, ['ls-tree', group.baseHead, '--', path])).stdout.split(' ')[0] || '100644';
|
|
235
|
+
files.push({ path, mode, blob: blob.stdout });
|
|
236
|
+
}
|
|
237
|
+
const branch = await freeBranchName(top, `${branchNameFrom(['baseline'], first.vcs?.branchPrefix || 'cop/')}/${first.id}`);
|
|
238
|
+
const sharing = group.sessions.filter((s) => (s.role === 'first' || s.role === 'shares') && !s.started);
|
|
239
|
+
const message = [
|
|
240
|
+
'Capture user-provided inputs',
|
|
241
|
+
'',
|
|
242
|
+
`The operator's input files, approved on the run screen, on top of "${group.baseBranch}" (${short(group.baseHead)}).`,
|
|
243
|
+
`Made without switching branches; the sessions ${names(sharing)} start from it. The work reads them and does not change them.`,
|
|
244
|
+
'',
|
|
245
|
+
...paths.slice(0, 200).map((p) => `- ${p}`),
|
|
246
|
+
'',
|
|
247
|
+
'Committed by copilot-operator. Not pushed.',
|
|
248
|
+
'',
|
|
249
|
+
].join('\n');
|
|
250
|
+
const made = await commitOnto(top, group.baseHead, files, message, branch);
|
|
251
|
+
if ('problem' in made)
|
|
252
|
+
return { ok: false, problem: made.problem };
|
|
253
|
+
const settings = inputSettings(first.vcs);
|
|
254
|
+
const sums = await inputSumsAt(top, made.commit, settings?.patterns ?? []);
|
|
255
|
+
const approvedAt = new Date().toISOString();
|
|
256
|
+
for (const s of sharing) {
|
|
257
|
+
const start = {
|
|
258
|
+
kind: 'snapshot',
|
|
259
|
+
commit: made.commit,
|
|
260
|
+
branch,
|
|
261
|
+
snapshot: {
|
|
262
|
+
fromBranch: group.baseBranch,
|
|
263
|
+
fromCommit: group.baseHead,
|
|
264
|
+
included: paths.slice(0, 500),
|
|
265
|
+
leftOut: [],
|
|
266
|
+
approved: true,
|
|
267
|
+
onBase: true,
|
|
268
|
+
approvedAt,
|
|
269
|
+
sharedWith: sharing.map((x) => ({ id: x.id, name: x.name })),
|
|
270
|
+
},
|
|
271
|
+
inputs: { patterns: settings?.patterns ?? [], files: sums, readOnly: settings?.readOnly ?? true },
|
|
272
|
+
};
|
|
273
|
+
await saveSession(s.id, (x) => {
|
|
274
|
+
x.vcsBaseCommit = made.commit;
|
|
275
|
+
x.vcsStart = start;
|
|
276
|
+
});
|
|
277
|
+
bus.publish({
|
|
278
|
+
sessionId: s.id,
|
|
279
|
+
type: 'vcs-snapshot',
|
|
280
|
+
level: 'info',
|
|
281
|
+
message: `starting snapshot approved on the run screen: ${paths.length} input file(s) on top of ${group.baseBranch} (${short(group.baseHead)}) as ${short(made.commit)} on ${branch}; the checkout was not touched`,
|
|
282
|
+
data: { commit: made.commit, branch, base: group.baseHead, baseBranch: group.baseBranch, inputs: paths, approvedAt, sessions: sharing.map((x) => x.id) },
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return { ok: true, result: `taken: ${short(made.commit)} on ${branch}, on top of "${group.baseBranch}"; ${names(sharing)} start from it.` };
|
|
286
|
+
}
|
package/dist/src/vcs/taskVcs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { findSuspicious } from './commitHygiene.js';
|
|
2
2
|
import { dirtyPolicy, planSnapshot, someOf, takeSnapshot } from './snapshot.js';
|
|
3
|
-
import { inputSettings, inputsNote, settleInputs } from './inputs.js';
|
|
3
|
+
import { dirtyBesidesInputs, inputSettings, inputsNote, settleInputs } from './inputs.js';
|
|
4
4
|
import { artifactPatterns, excludeArtifacts } from './artifacts.js';
|
|
5
5
|
import { workingTreePaths } from './git.js';
|
|
6
6
|
import { inScope } from './scope.js';
|
|
@@ -133,6 +133,19 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
133
133
|
state = await repoState(dir);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
+
/*
|
|
137
|
+
* Input files taken into a starting snapshot on the base branch stay untracked where they are, as
|
|
138
|
+
* they were approved: not "a dirty tree" while their content is the recorded one. They are staged
|
|
139
|
+
* when the task's branch is checked out, so the switch keeps them (see `switchTo`).
|
|
140
|
+
*/
|
|
141
|
+
let carryInputs = [];
|
|
142
|
+
if (state.dirty && start?.inputs) {
|
|
143
|
+
const split = await dirtyBesidesInputs(dir, start);
|
|
144
|
+
if (split.other.length === 0 && split.inputs.length > 0) {
|
|
145
|
+
carryInputs = split.inputs;
|
|
146
|
+
state = { ...state, dirty: false };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
136
149
|
// A dirty tree is the operator's own work in progress. Committing it under the bot's name
|
|
137
150
|
// or moving it to another branch would both be decisions that are not ours to make — unless
|
|
138
151
|
// the operator made it, with a snapshot policy, above.
|
|
@@ -190,7 +203,7 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
190
203
|
const attempt = task.attempt ?? 1;
|
|
191
204
|
const prefix = settings.branchPrefix || 'cop/';
|
|
192
205
|
if (settings.branchMode === 'per-session') {
|
|
193
|
-
return await switchTo(session, task, dir, sessionBranchName(session), base, bus, { reuseExisting: true, start });
|
|
206
|
+
return await switchTo(session, task, dir, sessionBranchName(session), base, bus, { reuseExisting: true, start, stage: carryInputs });
|
|
194
207
|
}
|
|
195
208
|
// A name the task carries wins over one derived from its title: whoever wrote the plan knew
|
|
196
209
|
// what the task was for, and a title is only ever a label for the list.
|
|
@@ -203,11 +216,11 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
203
216
|
// The same for a new prompt given to a finished task: it builds on that attempt's work.
|
|
204
217
|
const previousBranch = task.continuing || task.buildsOn ? task.attempts?.at(-1)?.vcs?.branch : undefined;
|
|
205
218
|
if (previousBranch)
|
|
206
|
-
return await switchTo(session, task, dir, previousBranch, base, bus, { reuseExisting: true, start });
|
|
219
|
+
return await switchTo(session, task, dir, previousBranch, base, bus, { reuseExisting: true, start, stage: carryInputs });
|
|
207
220
|
// A re-run starts from where that task started the first time, not from where the previous
|
|
208
221
|
// attempt ended. That is the whole point of recording the base commit.
|
|
209
222
|
const from = firstAttemptBase(task) ?? base;
|
|
210
|
-
return await switchTo(session, task, dir, wanted, from, bus, { reuseExisting: false, start });
|
|
223
|
+
return await switchTo(session, task, dir, wanted, from, bus, { reuseExisting: false, start, stage: carryInputs });
|
|
211
224
|
}
|
|
212
225
|
/**
|
|
213
226
|
* The one branch a `per-session` session works on: the name it was given, else one made from its
|
|
@@ -364,6 +377,7 @@ export async function sessionStart(session, dir, head, allSessions) {
|
|
|
364
377
|
commit: startedAt,
|
|
365
378
|
...(before.vcsStart?.branch ? { branch: before.vcsStart.branch } : {}),
|
|
366
379
|
fromSession: { id: before.id, name: before.name },
|
|
380
|
+
...inheritedBaseline(before),
|
|
367
381
|
note: artifactsOnly
|
|
368
382
|
? `"${before.name}" committed nothing — its result is artifacts only — so this session starts where it started (${startedAt.slice(0, 8)})`
|
|
369
383
|
: `"${before.name}" changed nothing, so this session starts where it started (${startedAt.slice(0, 8)})`,
|
|
@@ -403,7 +417,7 @@ export async function sessionStart(session, dir, head, allSessions) {
|
|
|
403
417
|
'or run that session "One branch for the whole session" so the next one can carry on from it.',
|
|
404
418
|
};
|
|
405
419
|
}
|
|
406
|
-
return { start: { kind: 'previous-session', commit: tip, branch: best.branch, fromSession: { id: best.session.id, name: best.session.name } } };
|
|
420
|
+
return { start: { kind: 'previous-session', commit: tip, branch: best.branch, fromSession: { id: best.session.id, name: best.session.name }, ...inheritedBaseline(best.session) } };
|
|
407
421
|
}
|
|
408
422
|
/**
|
|
409
423
|
* The branch holding a session's latest work, and when that work ended: in `per-session` mode its
|
|
@@ -422,6 +436,15 @@ function lastWorkOf(session) {
|
|
|
422
436
|
}
|
|
423
437
|
return best;
|
|
424
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* The starting snapshot a session carries on, for the one that continues it: its own when it made
|
|
441
|
+
* one, else the one it inherited. Recorded so the export can say each session of a chain shares it.
|
|
442
|
+
*/
|
|
443
|
+
function inheritedBaseline(before) {
|
|
444
|
+
const own = before.vcsStart?.kind === 'snapshot' ? { commit: before.vcsStart.commit, branch: before.vcsStart.branch, fromSession: { id: before.id, name: before.name } } : undefined;
|
|
445
|
+
const baseline = own ?? before.vcsStart?.baseline;
|
|
446
|
+
return baseline ? { baseline } : {};
|
|
447
|
+
}
|
|
425
448
|
/** When a session last did anything: the latest start or end of any of its tasks' attempts. */
|
|
426
449
|
function lastActivityOf(session) {
|
|
427
450
|
let at = null;
|
|
@@ -499,6 +522,10 @@ opts) {
|
|
|
499
522
|
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-problem', level: 'warn', message: problem });
|
|
500
523
|
return { vcs: { problem }, note: '' };
|
|
501
524
|
}
|
|
525
|
+
// Approved inputs left untracked where they are: staged first, so the switch keeps them.
|
|
526
|
+
const stage = opts.stage ?? [];
|
|
527
|
+
if (stage.length > 0)
|
|
528
|
+
await git(dir, ['--literal-pathspecs', 'add', '-f', '--', ...stage]);
|
|
502
529
|
const state = await repoState(dir);
|
|
503
530
|
let name = wantedName;
|
|
504
531
|
let result;
|
|
@@ -514,6 +541,9 @@ opts) {
|
|
|
514
541
|
result = await createBranch(dir, name, from);
|
|
515
542
|
}
|
|
516
543
|
if (!result.ok) {
|
|
544
|
+
// The operator's checkout as it was: the staged inputs go back to untracked.
|
|
545
|
+
if (stage.length > 0)
|
|
546
|
+
await git(dir, ['--literal-pathspecs', 'restore', '--staged', '--', ...stage]);
|
|
517
547
|
const problem = result.stderr || result.stdout || 'the branch could not be created';
|
|
518
548
|
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-problem', level: 'warn',
|
|
519
549
|
message: `version control is on but inactive: ${problem}` });
|
|
@@ -927,7 +957,13 @@ export async function vcsPreflight(session, allSessions = async () => []) {
|
|
|
927
957
|
return { ok: false, repoDir, problem: state.problem };
|
|
928
958
|
// Artifacts do not count: the run keeps them out of git before it looks (see `excludeArtifacts`).
|
|
929
959
|
const artifacts = artifactPatterns(settings);
|
|
930
|
-
|
|
960
|
+
// File by file when anything is to be told apart: plain status folds a new folder into one line.
|
|
961
|
+
let changed = state.dirty && (artifacts.length > 0 || !!session.vcsStart?.inputs) ? (await workingTreePaths(repoDir)).filter((p) => !artifacts.length || !inScope(p, artifacts)) : state.changed;
|
|
962
|
+
// Approved inputs left untracked as they were (a snapshot on the base branch) are not dirt either.
|
|
963
|
+
if (changed.length > 0 && session.vcsStart?.inputs) {
|
|
964
|
+
const split = await dirtyBesidesInputs(repoDir, session.vcsStart);
|
|
965
|
+
changed = changed.filter((p) => !split.inputs.includes(p));
|
|
966
|
+
}
|
|
931
967
|
const dirty = changed.length > 0;
|
|
932
968
|
/*
|
|
933
969
|
* Before the first task, under a snapshot policy or with input files: the list to approve, file by
|
package/dist/web/404.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--9Ze8aagkvT_WLfD4KCKKS--><html lang="en" data-theme="light" data-textsize="normal" data-contrast="normal" data-motion="normal" data-links="plain" data-focus="normal"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/c37978b44194c37b.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-0f31b926d9a9c5a4.js"/><script src="/_next/static/chunks/c7879cf7-b5ab1053c1d9a2e7.js" async=""></script><script src="/_next/static/chunks/131-bae98f790a541679.js" async=""></script><script src="/_next/static/chunks/main-app-e3a5f713ba31557e.js" async=""></script><script src="/_next/static/chunks/197-f7c33a0114fc3db3.js" async=""></script><script src="/_next/static/chunks/867-79f07bebe3084811.js" async=""></script><script src="/_next/static/chunks/549-5f90780046c1c24f.js" async=""></script><script src="/_next/static/chunks/app/layout-3efbb282292ccc38.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>copilot-operator</title><meta name="description" content="Runs task loops with Microsoft 365 Copilot on this machine."/><script>
|
|
2
2
|
(function () {
|
|
3
3
|
try {
|
|
4
4
|
var d = document.documentElement;
|
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
d.dataset.focus = a.strongFocus ? 'strong' : 'normal';
|
|
14
14
|
} catch (e) {}
|
|
15
15
|
})();
|
|
16
|
-
</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><a class="skip-link" href="#main">Skip to the content</a><div class="wrap"><header class="top"><h1><a href="/">copilot-operator</a></h1><nav aria-label="Main"><a href="/"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M4 5h16v4H4zM4 11h16v4H4zM4 17h10v2H4z"></path></svg><span>Sessions</span></a><a href="/defaults"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm8.5 4 1.5 1-1.6 2.8-1.8-.4a7 7 0 0 1-1.5 1.5l.4 1.8L14.7 21l-1-1.5a7 7 0 0 1-3.4 0l-1 1.5-2.8-1.6.4-1.8A7 7 0 0 1 5.4 16l-1.8.4L2 13.6 3.5 12.6V11.4L2 10.4l1.6-2.8 1.8.4A7 7 0 0 1 6.9 6.5l-.4-1.8L9.3 3l1 1.5a7 7 0 0 1 3.4 0l1-1.5 2.8 1.6-.4 1.8a7 7 0 0 1 1.5 1.5l1.8-.4L22 10.4l-1.5 1z"></path></svg><span>Settings</span></a><a href="/import"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 3v10m0 0 4-4m-4 4-4-4M4 15v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg><span>Plan from JSON</span></a><a href="/history"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 3a9 9 0 1 0 8.5 6M12 7v5l3 2M3 4v5h5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg><span>Task register</span></a><a href="/level1"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M6 3h9l5 5v13H6zM14 3v6h6M9 13h7M9 17h7" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"></path></svg><span>Level 1 prompt</span></a><a href="/presets"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M5 4h14v4H5zM5 10h14v4H5zM5 16h9v4H5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"></path></svg><span>Level 2 presets</span></a><a href="/appearance"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 3a9 9 0 0 0 0 18c1.5 0 2-1 2-2s-1-1.5-1-2.5S14 15 15.5 15H17a4 4 0 0 0 4-4 8 8 0 0 0-9-8zM8 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm4-3a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm4 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"></path></svg><span>Appearance</span></a><a href="/system"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M4 5h16v10H4zM2 19h20M9 15v4M15 15v4" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"></path></svg><span>System</span></a><select aria-label="Language" style="width:auto"><option value="en" selected="">English</option><option value="bg">Български</option></select></nav></header><main id="main"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/webpack-0f31b926d9a9c5a4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[8078,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"AppearanceProvider\"]\n3:I[867,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"LanguageProvider\"]\n4:I[1035,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"DialogHost\"]\n5:I[8214,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"SkipLink\"]\n6:I[8197,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"\"]\n7:I[8214,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"Nav\"]\n8:I[6657,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"GlobalApprovals\"]\n9:I[5204,[],\"\"]\na:I[2642,[],\"\"]\nb:I[7712,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-d9c54f7a2b285b3f.js\",\"549\",\"static/chunks/549-5d7c845fb0a27dbe.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"ScrollJump\"]\nc:I[433,[],\"OutletBoundary\"]\ne:I[9884,[],\"AsyncMetadataOutlet\"]\n10:I[433,[],\"ViewportBoundary\"]\n12:I[433,[],\"MetadataBoundary\"]\n13:\"$Sreact.suspense\"\n15:I[3536,[],\"\"]\n:HL[\"/_next/static/css/c37978b44194c37b.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"P0lpNIJvdSO3yuWRpIPQf\",\"p\":\"\",\"c\":[\"\",\"_not-found\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/c37978b44194c37b.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"suppressHydrationWarning\":true,\"data-theme\":\"light\",\"data-textsize\":\"normal\",\"data-contrast\":\"normal\",\"data-motion\":\"normal\",\"data-links\":\"plain\",\"data-focus\":\"normal\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n(function () {\\n try {\\n var d = document.documentElement;\\n var raw = localStorage.getItem('cop.appearance');\\n var a = raw ? JSON.parse(raw) : {};\\n if (!a || typeof a !== 'object') a = {};\\n d.dataset.theme = a.theme === 'dark' ? 'dark' : 'light';\\n d.dataset.textsize = [\\\"small\\\",\\\"normal\\\",\\\"large\\\",\\\"huge\\\",\\\"giant\\\"].indexOf(a.textSize) \u003e= 0 ? a.textSize : 'normal';\\n d.dataset.contrast = a.highContrast ? 'high' : 'normal';\\n d.dataset.motion = a.reduceMotion ? 'reduced' : 'normal';\\n d.dataset.links = a.underlineLinks ? 'underline' : 'plain';\\n d.dataset.focus = a.strongFocus ? 'strong' : 'normal';\\n } catch (e) {}\\n})();\\n\"}}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"div\",null,{\"className\":\"wrap\",\"children\":[[\"$\",\"header\",null,{\"className\":\"top\",\"children\":[[\"$\",\"h1\",null,{\"children\":[\"$\",\"$L6\",null,{\"href\":\"/\",\"children\":\"copilot-operator\"}]}],[\"$\",\"$L7\",null,{}]]}],[\"$\",\"$L8\",null,{}],[\"$\",\"main\",null,{\"id\":\"main\",\"children\":[\"$\",\"$L9\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$La\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}],[\"$\",\"$Lb\",null,{}]]}]}]}]}]]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L9\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$La\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$Lc\",null,{\"children\":[\"$Ld\",[\"$\",\"$Le\",null,{\"promise\":\"$@f\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L10\",null,{\"children\":\"$L11\"}],null],[\"$\",\"$L12\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$13\",null,{\"fallback\":null,\"children\":\"$L14\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$15\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"11:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\nd:null\n"])</script><script>self.__next_f.push([1,"f:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"copilot-operator\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Runs task loops with Microsoft 365 Copilot on this machine.\"}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"14:\"$f:metadata\"\n"])</script></body></html>
|
|
16
|
+
</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><a class="skip-link" href="#main">Skip to the content</a><div class="wrap"><header class="top"><h1><a href="/">copilot-operator</a></h1><nav aria-label="Main"><a href="/"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M4 5h16v4H4zM4 11h16v4H4zM4 17h10v2H4z"></path></svg><span>Sessions</span></a><a href="/defaults"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm8.5 4 1.5 1-1.6 2.8-1.8-.4a7 7 0 0 1-1.5 1.5l.4 1.8L14.7 21l-1-1.5a7 7 0 0 1-3.4 0l-1 1.5-2.8-1.6.4-1.8A7 7 0 0 1 5.4 16l-1.8.4L2 13.6 3.5 12.6V11.4L2 10.4l1.6-2.8 1.8.4A7 7 0 0 1 6.9 6.5l-.4-1.8L9.3 3l1 1.5a7 7 0 0 1 3.4 0l1-1.5 2.8 1.6-.4 1.8a7 7 0 0 1 1.5 1.5l1.8-.4L22 10.4l-1.5 1z"></path></svg><span>Settings</span></a><a href="/import"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 3v10m0 0 4-4m-4 4-4-4M4 15v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg><span>Plan from JSON</span></a><a href="/history"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 3a9 9 0 1 0 8.5 6M12 7v5l3 2M3 4v5h5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg><span>Task register</span></a><a href="/level1"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M6 3h9l5 5v13H6zM14 3v6h6M9 13h7M9 17h7" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"></path></svg><span>Level 1 prompt</span></a><a href="/presets"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M5 4h14v4H5zM5 10h14v4H5zM5 16h9v4H5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"></path></svg><span>Level 2 presets</span></a><a href="/appearance"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 3a9 9 0 0 0 0 18c1.5 0 2-1 2-2s-1-1.5-1-2.5S14 15 15.5 15H17a4 4 0 0 0 4-4 8 8 0 0 0-9-8zM8 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm4-3a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm4 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"></path></svg><span>Appearance</span></a><a href="/system"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M4 5h16v10H4zM2 19h20M9 15v4M15 15v4" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"></path></svg><span>System</span></a><select aria-label="Language" style="width:auto"><option value="en" selected="">English</option><option value="bg">Български</option></select></nav></header><main id="main"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/webpack-0f31b926d9a9c5a4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[8078,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"AppearanceProvider\"]\n3:I[867,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"LanguageProvider\"]\n4:I[1035,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"DialogHost\"]\n5:I[8214,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"SkipLink\"]\n6:I[8197,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"\"]\n7:I[8214,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"Nav\"]\n8:I[6657,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"GlobalApprovals\"]\n9:I[5204,[],\"\"]\na:I[2642,[],\"\"]\nb:I[7712,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-79f07bebe3084811.js\",\"549\",\"static/chunks/549-5f90780046c1c24f.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"ScrollJump\"]\nc:I[433,[],\"OutletBoundary\"]\ne:I[9884,[],\"AsyncMetadataOutlet\"]\n10:I[433,[],\"ViewportBoundary\"]\n12:I[433,[],\"MetadataBoundary\"]\n13:\"$Sreact.suspense\"\n15:I[3536,[],\"\"]\n:HL[\"/_next/static/css/c37978b44194c37b.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"9Ze8aagkvT-WLfD4KCKKS\",\"p\":\"\",\"c\":[\"\",\"_not-found\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/c37978b44194c37b.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"suppressHydrationWarning\":true,\"data-theme\":\"light\",\"data-textsize\":\"normal\",\"data-contrast\":\"normal\",\"data-motion\":\"normal\",\"data-links\":\"plain\",\"data-focus\":\"normal\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n(function () {\\n try {\\n var d = document.documentElement;\\n var raw = localStorage.getItem('cop.appearance');\\n var a = raw ? JSON.parse(raw) : {};\\n if (!a || typeof a !== 'object') a = {};\\n d.dataset.theme = a.theme === 'dark' ? 'dark' : 'light';\\n d.dataset.textsize = [\\\"small\\\",\\\"normal\\\",\\\"large\\\",\\\"huge\\\",\\\"giant\\\"].indexOf(a.textSize) \u003e= 0 ? a.textSize : 'normal';\\n d.dataset.contrast = a.highContrast ? 'high' : 'normal';\\n d.dataset.motion = a.reduceMotion ? 'reduced' : 'normal';\\n d.dataset.links = a.underlineLinks ? 'underline' : 'plain';\\n d.dataset.focus = a.strongFocus ? 'strong' : 'normal';\\n } catch (e) {}\\n})();\\n\"}}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"div\",null,{\"className\":\"wrap\",\"children\":[[\"$\",\"header\",null,{\"className\":\"top\",\"children\":[[\"$\",\"h1\",null,{\"children\":[\"$\",\"$L6\",null,{\"href\":\"/\",\"children\":\"copilot-operator\"}]}],[\"$\",\"$L7\",null,{}]]}],[\"$\",\"$L8\",null,{}],[\"$\",\"main\",null,{\"id\":\"main\",\"children\":[\"$\",\"$L9\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$La\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}],[\"$\",\"$Lb\",null,{}]]}]}]}]}]]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L9\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$La\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$Lc\",null,{\"children\":[\"$Ld\",[\"$\",\"$Le\",null,{\"promise\":\"$@f\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L10\",null,{\"children\":\"$L11\"}],null],[\"$\",\"$L12\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$13\",null,{\"fallback\":null,\"children\":\"$L14\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$15\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"11:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\nd:null\n"])</script><script>self.__next_f.push([1,"f:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"copilot-operator\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Runs task loops with Microsoft 365 Copilot on this machine.\"}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"14:\"$f:metadata\"\n"])</script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[549],{5549:(t,e,o)=>{o.d(e,{AV:()=>a,FH:()=>h,FZ:()=>r,Zm:()=>u,aT:()=>s,c5:()=>y,dK:()=>l,nC:()=>n,rt:()=>d,ub:()=>i,zi:()=>p});let n="/api";function s(t,e){return"/sessions/view?id=".concat(encodeURIComponent(t)).concat(e?"#".concat(e):"")}let c="cop-api-token";function a(){try{let t=/(?:^#|&)token=([0-9a-f]{16,})/i.exec(window.location.hash);if(t)return window.localStorage.setItem(c,t[1]),window.history.replaceState(null,"",window.location.pathname+window.location.search),t[1];return window.localStorage.getItem(c)||""}catch(t){return""}}function i(t){let e=a();return e?"".concat(t).concat(t.includes("?")?"&":"?","token=").concat(encodeURIComponent(e)):t}let r=["exit-zero","exit-nonzero","output-contains","output-omits","output-matches","file-exists","file-missing","file-contains"];function d(t){return t.startsWith("exit-")||t.startsWith("output-")}function l(t){return"output-contains"===t||"output-omits"===t||"output-matches"===t||"file-contains"===t}function u(t){return"limit-reached"===t.status||"aborted"===t.status||!!t.limit&&("failed"===t.status||"blocked"===t.status)}async function m(t,e){let o,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},c=void 0===s.timeoutMs?3e4:s.timeoutMs;try{var i;o=await fetch("".concat(n).concat(t),{...e,...null!==c&&!(null==e?void 0:e.signal)?{signal:AbortSignal.timeout(c)}:{},headers:{"content-type":"application/json",...a()?{"x-cop-token":a()}:{},...null!=(i=null==e?void 0:e.headers)?i:{}}})}catch(e){if("TimeoutError"===e.name)throw Error("The API did not answer within ".concat(Math.round((null!=c?c:0)/1e3)," s (").concat(t.split("?")[0],"). It may be busy; try again."));throw e}if(!o.ok){let t="".concat(o.status," ").concat(o.statusText);try{let e=await o.json();(null==e?void 0:e.message)&&(t=Array.isArray(e.message)?e.message.join("; "):e.message)}catch(t){}throw Error(t)}let r=await o.text();return r?JSON.parse(r):void 0}let h={health:()=>m("/health"),doctor:()=>m("/doctor"),settings:()=>m("/settings"),saveSettings:t=>m("/settings",{method:"PUT",body:JSON.stringify(t)}),level1:()=>m("/level1"),setLevel1:t=>m("/level1",{method:"PUT",body:JSON.stringify({content:t})}),resetLevel1:()=>m("/level1",{method:"DELETE"}),presets:()=>m("/presets"),savePreset:(t,e)=>m("/presets/".concat(encodeURIComponent(t)),{method:"PUT",body:JSON.stringify({content:e})}),deletePreset:t=>m("/presets/".concat(encodeURIComponent(t)),{method:"DELETE"}),personas:()=>m("/personas"),savePersona:(t,e)=>m("/personas/".concat(encodeURIComponent(t)),{method:"PUT",body:JSON.stringify({content:e})}),deletePersona:t=>m("/personas/".concat(encodeURIComponent(t)),{method:"DELETE"}),sessions:()=>m("/sessions"),reorderSessions:t=>m("/sessions-order",{method:"PUT",body:JSON.stringify({ids:t})}),metrics:()=>m("/metrics"),preparePreview:t=>m("/repo/prepare/preview",{method:"POST",body:JSON.stringify({dir:t})}),prepareProject:(t,e)=>m("/repo/prepare",{method:"POST",body:JSON.stringify({dir:t,fingerprint:e})}),session:t=>m("/sessions/".concat(t)),createSession:(t,e)=>m("/sessions",{method:"POST",body:JSON.stringify({name:t,projectDir:e})}),updateSession:(t,e)=>m("/sessions/".concat(t),{method:"PUT",body:JSON.stringify(e)}),deleteSession:t=>m("/sessions/".concat(t),{method:"DELETE"}),addTask:(t,e)=>m("/sessions/".concat(t,"/tasks"),{method:"POST",body:JSON.stringify(e)}),updateTask:(t,e,o)=>m("/sessions/".concat(t,"/tasks/").concat(e),{method:"PUT",body:JSON.stringify(o)}),deleteTask:(t,e)=>m("/sessions/".concat(t,"/tasks/").concat(e),{method:"DELETE"}),continueTask:(t,e)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/continue"),{method:"POST",body:"{}"}),rerunTask:function(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return m("/sessions/".concat(t,"/tasks/").concat(e,"/rerun"),{method:"POST",body:JSON.stringify({...o,...n.buildOnFinished?{buildOnFinished:!0}:{}})})},taskChanges:(t,e,o)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/changes").concat(o?"?run=".concat(encodeURIComponent(o)):"")),taskChangeFile:(t,e,o,n)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/changes/file?path=").concat(encodeURIComponent(o)).concat(n?"&run=".concat(encodeURIComponent(n)):"")),taskStory:(t,e,o)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/story").concat(o?"?run=".concat(encodeURIComponent(o)):"")),taskFiles:(t,e,o)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/files").concat(o?"?run=".concat(encodeURIComponent(o)):"")),taskLogUrl:(t,e,o)=>"".concat(n,"/sessions/").concat(t,"/tasks/").concat(e,"/log").concat(o?"?run=".concat(encodeURIComponent(o)):""),taskFileUrl:(t,e,o,s,c)=>"".concat(n,"/sessions/").concat(t,"/tasks/").concat(e,"/files/").concat(o,"/").concat(encodeURIComponent(s)).concat(c?"?run=".concat(encodeURIComponent(c)):""),saveTaskLog:(t,e,o)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/log").concat(o?"?run=".concat(encodeURIComponent(o)):""),{method:"POST",body:"{}"}),saveTaskFile:(t,e,o,n,s)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/files/").concat(o,"/").concat(encodeURIComponent(n)).concat(s?"?run=".concat(encodeURIComponent(s)):""),{method:"POST",body:"{}"}),start:(t,e,o)=>m("/sessions/".concat(t,"/start"),{method:"POST",body:JSON.stringify({mode:e,name:o})}),stop:t=>m("/sessions/".concat(t,"/stop"),{method:"POST",body:"{}"}),approvals:t=>m("/approvals".concat(t?"?session=".concat(encodeURIComponent(t)):"")),decide:(t,e)=>m("/approvals/".concat(t),{method:"POST",body:JSON.stringify({action:e})}),setRunMode:(t,e)=>m("/sessions/".concat(t,"/mode"),{method:"POST",body:JSON.stringify({mode:e})}),streamUrl:t=>i("".concat(n,"/sessions/").concat(t,"/stream")),batch:()=>m("/batch").then(t=>null!=t?t:null),startBatch:(t,e,o,n,s,c,a)=>m("/batch/start",{method:"POST",body:JSON.stringify({sessionIds:t,mode:e,onFailure:o,model:n,reviewModel:s,name:c,taskIds:a})}),suggestedRunName:t=>m("/batch/name?sessions=".concat(encodeURIComponent(t.join(",")))),stopBatch:()=>m("/batch/stop",{method:"POST",body:"{}"}),pauseBatch:()=>m("/batch/pause",{method:"POST",body:"{}"}),resumeBatch:()=>m("/batch/resume",{method:"POST",body:"{}"}),planBrief:t=>m("/plan/brief?lang=".concat(encodeURIComponent(t))),context:(t,e)=>m("/context/".concat(t,"?lang=").concat(encodeURIComponent(e))),setContext:(t,e)=>m("/context/".concat(t),{method:"PUT",body:JSON.stringify({content:e})}),resetContext:(t,e)=>m("/context/".concat(t,"?lang=").concat(encodeURIComponent(e)),{method:"DELETE"}),checkPlan:t=>m("/plan/check",{method:"POST",body:JSON.stringify({text:t})}),importPlan:t=>m("/plan/import",{method:"POST",body:JSON.stringify({text:t})}),browseFolder:t=>m("/browse-folder",{method:"POST",body:JSON.stringify({start:t})},{timeoutMs:null}),tasks:()=>m("/tasks"),activity:()=>m("/activity"),downloadBundle:async t=>{var e,o,s;let c=await fetch("".concat(n,"/export/bundle"),{method:"POST",headers:{"content-type":"application/json",...a()?{"x-cop-token":a()}:{}},body:JSON.stringify({tasks:t})});if(!c.ok)throw Error(await c.text()||"".concat(c.status," ").concat(c.statusText));let i=null!=(s=c.headers.get("content-disposition"))?s:"",r=null==(e=/filename\*=UTF-8''([^;]+)/i.exec(i))?void 0:e[1],d=null==(o=/filename="([^"]+)"/i.exec(i))?void 0:o[1],l=null!=d?d:"copilot-operator-bundle.json";if(r)try{l=decodeURIComponent(r)}catch(t){}let u=URL.createObjectURL(await c.blob()),m=document.createElement("a");return m.href=u,m.download=l,document.body.appendChild(m),m.click(),m.remove(),setTimeout(()=>URL.revokeObjectURL(u),1e4),l},exportUrl:(t,e)=>{let o=new URLSearchParams;return e.run&&o.set("run",e.run),e.session&&o.set("session",e.session),e.task&&o.set("task",e.task),i("".concat(n,"/export/").concat(t,"?").concat(o.toString()))},debugExportUrl:t=>i("".concat(n,"/debug/export").concat(t.length>0?"?sessions=".concat(encodeURIComponent(t.join(","))):"")),vcsStatus:t=>m("/sessions/".concat(t,"/vcs")),runVcs:t=>m("/batch/vcs?ids=".concat(encodeURIComponent(t.join(",")))),runVcsPrepare:function(t,e,o){let n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return m("/batch/vcs/prepare",{method:"POST",body:JSON.stringify({sessionIds:t,repoDir:e,action:o,choices:n})})},vcsSnapshot:(t,e)=>m("/sessions/".concat(t,"/vcs/snapshot"),{method:"POST",body:JSON.stringify({choices:e})}),restorePreview:(t,e)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/restore")),restore:(t,e)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/restore"),{method:"POST",body:"{}"}),restartPlan:(t,e)=>m("/sessions/".concat(t,"/tasks/").concat(e,"/restart")),restartFrom:function(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return m("/sessions/".concat(t,"/tasks/").concat(e,"/restart"),{method:"POST",body:JSON.stringify(o)})},repoCheck:t=>m("/repo?dir=".concat(encodeURIComponent(t))),project:()=>m("/project"),setProject:t=>m("/project",{method:"PUT",body:JSON.stringify(t)}),models:()=>m("/models"),setDefaultModel:t=>m("/models/default",{method:"PUT",body:JSON.stringify({model:t})}),setDefaultReviewModel:t=>m("/models/review-default",{method:"PUT",body:JSON.stringify({model:t})}),refreshModels:()=>m("/models/refresh",{method:"POST",body:"{}"},{timeoutMs:null}),login:t=>m("/login",{method:"POST",body:JSON.stringify({account:(null==t?void 0:t.trim())||void 0})},{timeoutMs:null})};function p(t){return t<1024?"".concat(t," B"):t<1048576?"".concat((t/1024).toFixed(1)," KB"):"".concat((t/1048576).toFixed(1)," MB")}function y(t){if(void 0===t)return"";let e=Math.round(t/1e3);if(e<60)return"".concat(e,"s");let o=Math.floor(e/60);return o<60?"".concat(o,"m ").concat(e%60,"s"):"".concat(Math.floor(o/60),"h ").concat(o%60,"m")}}}]);
|