copilot-operator 0.1.19 → 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 +72 -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 +60 -20
- 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 -147
- 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/{ofnRLEgWx9th5w_qtuFnB → 9Ze8aagkvT-WLfD4KCKKS}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{ofnRLEgWx9th5w_qtuFnB → 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.
|
|
@@ -146,6 +159,7 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
146
159
|
message: `version control cannot start: ${problem}` });
|
|
147
160
|
return { vcs: { problem }, note: '' };
|
|
148
161
|
}
|
|
162
|
+
let startIsNew = false;
|
|
149
163
|
if (!base) {
|
|
150
164
|
const resolved = await sessionStart(session, dir, state.head, allSessions);
|
|
151
165
|
if ('problem' in resolved) {
|
|
@@ -155,15 +169,13 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
155
169
|
}
|
|
156
170
|
start = resolved.start;
|
|
157
171
|
base = start?.commit;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
message: describeStart(chosen), data: { ...chosen } });
|
|
166
|
-
}
|
|
172
|
+
/*
|
|
173
|
+
* Recorded below, once the inputs are settled too, not here. Recorded here, a task refused for its
|
|
174
|
+
* inputs (a pattern matching nothing yet) left the session started: the retry, with the files added,
|
|
175
|
+
* skipped the starting snapshot and ran with version control off (reported on 0.1.18). A start that
|
|
176
|
+
* is refused records nothing, and the retry starts afresh.
|
|
177
|
+
*/
|
|
178
|
+
startIsNew = !!start;
|
|
167
179
|
}
|
|
168
180
|
/*
|
|
169
181
|
* The operator's input files, in the commit the session starts from whatever its `startFrom`, with
|
|
@@ -173,20 +185,25 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
173
185
|
const settled = await settleInputs(session, dir, start, allSessions);
|
|
174
186
|
if ('problem' in settled)
|
|
175
187
|
return refuse(`${settled.problem} Nothing was run.`);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
188
|
+
start = settled.start;
|
|
189
|
+
base = settled.start.commit;
|
|
190
|
+
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-inputs', level: 'info',
|
|
191
|
+
message: describeInputs(settled.start), data: { files: settled.start.inputs?.files.length ?? 0, carried: settled.start.inputs?.carried } });
|
|
192
|
+
startIsNew = true;
|
|
193
|
+
}
|
|
194
|
+
if (startIsNew && start) {
|
|
195
|
+
const chosen = start;
|
|
179
196
|
await saveSession((s) => {
|
|
180
197
|
s.vcsBaseCommit = chosen.commit;
|
|
181
198
|
s.vcsStart = chosen;
|
|
182
199
|
});
|
|
183
|
-
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-
|
|
184
|
-
message:
|
|
200
|
+
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-start', level: chosen.note || updateWarns(chosen) ? 'warn' : 'info',
|
|
201
|
+
message: describeStart(chosen), data: { ...chosen } });
|
|
185
202
|
}
|
|
186
203
|
const attempt = task.attempt ?? 1;
|
|
187
204
|
const prefix = settings.branchPrefix || 'cop/';
|
|
188
205
|
if (settings.branchMode === 'per-session') {
|
|
189
|
-
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 });
|
|
190
207
|
}
|
|
191
208
|
// A name the task carries wins over one derived from its title: whoever wrote the plan knew
|
|
192
209
|
// what the task was for, and a title is only ever a label for the list.
|
|
@@ -199,11 +216,11 @@ async function prepare(session, task, bus, saveSession, allSessions) {
|
|
|
199
216
|
// The same for a new prompt given to a finished task: it builds on that attempt's work.
|
|
200
217
|
const previousBranch = task.continuing || task.buildsOn ? task.attempts?.at(-1)?.vcs?.branch : undefined;
|
|
201
218
|
if (previousBranch)
|
|
202
|
-
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 });
|
|
203
220
|
// A re-run starts from where that task started the first time, not from where the previous
|
|
204
221
|
// attempt ended. That is the whole point of recording the base commit.
|
|
205
222
|
const from = firstAttemptBase(task) ?? base;
|
|
206
|
-
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 });
|
|
207
224
|
}
|
|
208
225
|
/**
|
|
209
226
|
* The one branch a `per-session` session works on: the name it was given, else one made from its
|
|
@@ -360,6 +377,7 @@ export async function sessionStart(session, dir, head, allSessions) {
|
|
|
360
377
|
commit: startedAt,
|
|
361
378
|
...(before.vcsStart?.branch ? { branch: before.vcsStart.branch } : {}),
|
|
362
379
|
fromSession: { id: before.id, name: before.name },
|
|
380
|
+
...inheritedBaseline(before),
|
|
363
381
|
note: artifactsOnly
|
|
364
382
|
? `"${before.name}" committed nothing — its result is artifacts only — so this session starts where it started (${startedAt.slice(0, 8)})`
|
|
365
383
|
: `"${before.name}" changed nothing, so this session starts where it started (${startedAt.slice(0, 8)})`,
|
|
@@ -399,7 +417,7 @@ export async function sessionStart(session, dir, head, allSessions) {
|
|
|
399
417
|
'or run that session "One branch for the whole session" so the next one can carry on from it.',
|
|
400
418
|
};
|
|
401
419
|
}
|
|
402
|
-
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) } };
|
|
403
421
|
}
|
|
404
422
|
/**
|
|
405
423
|
* The branch holding a session's latest work, and when that work ended: in `per-session` mode its
|
|
@@ -418,6 +436,15 @@ function lastWorkOf(session) {
|
|
|
418
436
|
}
|
|
419
437
|
return best;
|
|
420
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
|
+
}
|
|
421
448
|
/** When a session last did anything: the latest start or end of any of its tasks' attempts. */
|
|
422
449
|
function lastActivityOf(session) {
|
|
423
450
|
let at = null;
|
|
@@ -495,6 +522,10 @@ opts) {
|
|
|
495
522
|
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-problem', level: 'warn', message: problem });
|
|
496
523
|
return { vcs: { problem }, note: '' };
|
|
497
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]);
|
|
498
529
|
const state = await repoState(dir);
|
|
499
530
|
let name = wantedName;
|
|
500
531
|
let result;
|
|
@@ -510,6 +541,9 @@ opts) {
|
|
|
510
541
|
result = await createBranch(dir, name, from);
|
|
511
542
|
}
|
|
512
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]);
|
|
513
547
|
const problem = result.stderr || result.stdout || 'the branch could not be created';
|
|
514
548
|
bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-problem', level: 'warn',
|
|
515
549
|
message: `version control is on but inactive: ${problem}` });
|
|
@@ -923,7 +957,13 @@ export async function vcsPreflight(session, allSessions = async () => []) {
|
|
|
923
957
|
return { ok: false, repoDir, problem: state.problem };
|
|
924
958
|
// Artifacts do not count: the run keeps them out of git before it looks (see `excludeArtifacts`).
|
|
925
959
|
const artifacts = artifactPatterns(settings);
|
|
926
|
-
|
|
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
|
+
}
|
|
927
967
|
const dirty = changed.length > 0;
|
|
928
968
|
/*
|
|
929
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\":\"ofnRLEgWx9th5w_qtuFnB\",\"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")}}}]);
|