copilot-operator 0.1.22 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/src/api/operator.controller.js +2 -2
  2. package/dist/src/api/operator.service.js +330 -35
  3. package/dist/src/exec/confinement.js +85 -7
  4. package/dist/src/exec/programs.js +12 -3
  5. package/dist/src/exec/reportFile.js +5 -3
  6. package/dist/src/exec/shells.js +13 -2
  7. package/dist/src/log/runLog.js +6 -1
  8. package/dist/src/orchestrator/contract.js +29 -7
  9. package/dist/src/orchestrator/review.js +16 -3
  10. package/dist/src/orchestrator/taskRunner.js +391 -54
  11. package/dist/src/plan/schema.js +11 -1
  12. package/dist/src/plan/systemGuide.js +36 -4
  13. package/dist/src/protocol/parser.js +33 -5
  14. package/dist/src/protocol/reporter.js +2 -0
  15. package/dist/src/session/compose.js +18 -9
  16. package/dist/src/session/exportRecord.js +12 -3
  17. package/dist/src/session/exports.js +46 -9
  18. package/dist/src/session/handoff.js +5 -2
  19. package/dist/src/session/interruption.js +3 -1
  20. package/dist/src/session/runLog.js +42 -1
  21. package/dist/src/session/runName.js +3 -1
  22. package/dist/src/session/store.js +7 -2
  23. package/dist/src/transport/copilotTransport.js +89 -62
  24. package/dist/src/transport/modelMatch.js +37 -0
  25. package/dist/src/vcs/artifacts.js +20 -7
  26. package/dist/src/vcs/commitHygiene.js +7 -2
  27. package/dist/src/vcs/contentIntegrity.js +65 -6
  28. package/dist/src/vcs/git.js +44 -7
  29. package/dist/src/vcs/prepareFromRemote.js +46 -9
  30. package/dist/src/vcs/remoteAuth.js +92 -0
  31. package/dist/src/vcs/runPreflight.js +100 -31
  32. package/dist/src/vcs/scope.js +18 -2
  33. package/dist/src/vcs/snapshot.js +61 -16
  34. package/dist/src/vcs/syncCommand.js +3 -11
  35. package/dist/src/vcs/taskVcs.js +173 -24
  36. package/dist/web/404.html +2 -2
  37. package/dist/web/_next/static/chunks/549-7e35e4fdefadb05d.js +1 -0
  38. package/dist/web/_next/static/chunks/867-52e371cb1ec49089.js +1 -0
  39. package/dist/web/_next/static/chunks/app/defaults/{page-cdc730adea753446.js → page-62c8fbe84baa436a.js} +1 -1
  40. package/dist/web/_next/static/chunks/app/page-4defcfd1eb482644.js +1 -0
  41. package/dist/web/_next/static/chunks/app/sessions/view/{page-185755ada66e2930.js → page-2d3bbc68b27fed2c.js} +1 -1
  42. package/dist/web/appearance.html +2 -2
  43. package/dist/web/appearance.txt +10 -10
  44. package/dist/web/defaults.html +2 -2
  45. package/dist/web/defaults.txt +10 -10
  46. package/dist/web/history.html +2 -2
  47. package/dist/web/history.txt +10 -10
  48. package/dist/web/import.html +2 -2
  49. package/dist/web/import.txt +10 -10
  50. package/dist/web/index.html +2 -2
  51. package/dist/web/index.txt +10 -10
  52. package/dist/web/level1.html +2 -2
  53. package/dist/web/level1.txt +10 -10
  54. package/dist/web/presets.html +2 -2
  55. package/dist/web/presets.txt +10 -10
  56. package/dist/web/sessions/view.html +2 -2
  57. package/dist/web/sessions/view.txt +10 -10
  58. package/dist/web/system.html +2 -2
  59. package/dist/web/system.txt +10 -10
  60. package/package.json +3 -2
  61. package/prompts/level1.md +10 -3
  62. package/dist/web/_next/static/chunks/549-5f90780046c1c24f.js +0 -1
  63. package/dist/web/_next/static/chunks/867-79f07bebe3084811.js +0 -1
  64. package/dist/web/_next/static/chunks/app/page-0a861b38da0a1c51.js +0 -1
  65. /package/dist/web/_next/static/{9Ze8aagkvT-WLfD4KCKKS → beP1HgHJZvBVRTsoU1sZv}/_buildManifest.js +0 -0
  66. /package/dist/web/_next/static/{9Ze8aagkvT-WLfD4KCKKS → beP1HgHJZvBVRTsoU1sZv}/_ssgManifest.js +0 -0
@@ -75,8 +75,8 @@ async function prepare(session, task, bus, saveSession, allSessions) {
75
75
  bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-artifacts-tracked', level: 'warn',
76
76
  message: `${excluded.tracked.length} artifact file(s) are already tracked by git, so a change to them is still committed: ${someOf(excluded.tracked)}. Take them out of git yourself (git rm --cached) if they should not be.` });
77
77
  }
78
- if (excluded.tracked.length > 0 || artifactPatterns(settings).length > 0)
79
- state = await repoState(dir);
78
+ // Read again: the exclude file may just have taken the scratch folder or artifacts out of what makes the tree dirty.
79
+ state = await repoState(dir);
80
80
  if (settings.startFrom === 'existing-branch')
81
81
  return await onExistingBranch(session, task, dir, state, bus, saveSession, allSessions);
82
82
  // The session's base is fixed the first time it runs: every per-task branch is cut from it,
@@ -150,11 +150,22 @@ async function prepare(session, task, bus, saveSession, allSessions) {
150
150
  // or moving it to another branch would both be decisions that are not ours to make — unless
151
151
  // the operator made it, with a snapshot policy, above.
152
152
  if (state.dirty) {
153
- const problem = `the repository has uncommitted changes (${state.changed.slice(0, 5).join(', ')}` +
154
- `${state.changed.length > 5 ? `, and ${state.changed.length - 5} more` : ''}). ` +
155
- (base
156
- ? 'Commit or stash them, so the task starts from a known state.'
157
- : 'Commit or stash them, or choose "Take them as a starting snapshot" under Version control → "Uncommitted changes" (input files: "Input files").');
153
+ /*
154
+ * With commits off, what an earlier task of this session wrote is still in the tree: that is how the
155
+ * session is set, not the operator's work to commit or stash (live run 2026-10-03). Said as it is: this
156
+ * task runs on top of it, without a branch of its own.
157
+ */
158
+ const earlierRan = session.tasks.some((t) => t.id !== task.id && t.status !== 'queued' && !!t.startedAt);
159
+ const commitsOff = settings.commitOnFinish === false;
160
+ const problem = commitsOff && earlierRan
161
+ ? `commits are off for this session, so the files the earlier task(s) left are still in the working tree (${state.changed.slice(0, 5).join(', ')}` +
162
+ `${state.changed.length > 5 ? `, and ${state.changed.length - 5} more` : ''}). This task runs on top of them, on ${state.branch ?? 'the current branch'}, without a branch of its own, and its scope is not enforced. ` +
163
+ 'For a branch per task, turn "Commit when a task finishes" on, or use one branch for the whole session.'
164
+ : `the repository has uncommitted changes (${state.changed.slice(0, 5).join(', ')}` +
165
+ `${state.changed.length > 5 ? `, and ${state.changed.length - 5} more` : ''}). ` +
166
+ (base
167
+ ? 'Commit or stash them, so the task starts from a known state.'
168
+ : 'Commit or stash them, or choose "Take them as a starting snapshot" under Version control → "Uncommitted changes" (input files: "Input files").');
158
169
  bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-dirty', level: 'warn',
159
170
  message: `version control cannot start: ${problem}` });
160
171
  return { vcs: { problem }, note: '' };
@@ -203,6 +214,38 @@ async function prepare(session, task, bus, saveSession, allSessions) {
203
214
  const attempt = task.attempt ?? 1;
204
215
  const prefix = settings.branchPrefix || 'cop/';
205
216
  if (settings.branchMode === 'per-session') {
217
+ /*
218
+ * "Run again" of a task whose last attempt did not end done starts again from where the task first
219
+ * started, as the button promises, and not on top of the failed attempt's commit (live run
220
+ * 2026-10-03: the re-run found the failed attempt's files, "already satisfied" them and committed
221
+ * nothing). Only when no other task of the session ran after this one: then the session's line moves
222
+ * to a new branch at that point, and the old one keeps the failed attempt. Otherwise the later work
223
+ * sits on top, and "Run again from here" is the way to take the whole chain back.
224
+ */
225
+ const previous = task.attempts?.at(-1);
226
+ const startedFirst = task.attempts?.[0]?.startedAt;
227
+ const laterRan = !!startedFirst && session.tasks.some((t) => t.id !== task.id && t.startedAt && t.startedAt > startedFirst);
228
+ const restartAt = !task.continuing && !task.buildsOn && previous && previous.status !== 'done' ? firstAttemptBase(task) : undefined;
229
+ // Already there — "Run again from here" or a Restore moved the session onto a branch at that point — then nothing to move.
230
+ const tipNow = (await git(dir, ['rev-parse', '--verify', '--quiet', `refs/heads/${sessionBranchName(session)}^{commit}`])).stdout;
231
+ if (restartAt && !laterRan && tipNow && tipNow !== restartAt) {
232
+ const left = sessionBranchName(session);
233
+ const fresh = await freeBranchName(dir, `${left}-a${attempt}`);
234
+ await saveSession((s) => {
235
+ if (s.vcs) {
236
+ s.vcs.branchName = fresh;
237
+ s.vcs.branchNameExact = true;
238
+ }
239
+ });
240
+ bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-session-branch', level: 'info',
241
+ message: `"${task.title}" runs again from where it first started (${restartAt.slice(0, 8)}), on ${fresh}; ${left} keeps the failed attempt`,
242
+ data: { branch: fresh, left, from: restartAt } });
243
+ return await switchTo(session, task, dir, fresh, restartAt, bus, { reuseExisting: false, start, stage: carryInputs });
244
+ }
245
+ if (restartAt && laterRan) {
246
+ bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-builds-on-failed', level: 'warn',
247
+ message: `"${task.title}" runs again on ${sessionBranchName(session)}, on top of its failed attempt, because later tasks of this session ran after it; use "Run again from here" to take the chain back to before it` });
248
+ }
206
249
  return await switchTo(session, task, dir, sessionBranchName(session), base, bus, { reuseExisting: true, start, stage: carryInputs });
207
250
  }
208
251
  // A name the task carries wins over one derived from its title: whoever wrote the plan knew
@@ -217,6 +260,19 @@ async function prepare(session, task, bus, saveSession, allSessions) {
217
260
  const previousBranch = task.continuing || task.buildsOn ? task.attempts?.at(-1)?.vcs?.branch : undefined;
218
261
  if (previousBranch)
219
262
  return await switchTo(session, task, dir, previousBranch, base, bus, { reuseExisting: true, start, stage: carryInputs });
263
+ /*
264
+ * The previous attempt committed nothing and its branch is still where it was cut: that branch is
265
+ * taken again rather than leaving it empty beside a new "-a2" that holds the work (live run 2026-10-03,
266
+ * a fresh-chat retry). The branch the task first started from is the same commit, so nothing changes
267
+ * about where the attempt stands.
268
+ */
269
+ const prev = task.attempts?.at(-1);
270
+ if (prev?.vcs?.branch && prev.vcs.baseCommit && !prev.vcs.commit && prev.vcs.baseCommit === firstAttemptBase(task)) {
271
+ const tip = (await git(dir, ['rev-parse', '--verify', '--quiet', `refs/heads/${prev.vcs.branch}^{commit}`])).stdout;
272
+ if (tip && tip === prev.vcs.baseCommit) {
273
+ return await switchTo(session, task, dir, prev.vcs.branch, prev.vcs.baseCommit, bus, { reuseExisting: true, start, stage: carryInputs });
274
+ }
275
+ }
220
276
  // A re-run starts from where that task started the first time, not from where the previous
221
277
  // attempt ended. That is the whole point of recording the base commit.
222
278
  const from = firstAttemptBase(task) ?? base;
@@ -314,14 +370,16 @@ async function onExistingBranch(session, task, dir, state, bus, saveSession, all
314
370
  * When there is none, it starts from `baseBranch` and says so, rather than from wherever the
315
371
  * repository happens to be.
316
372
  */
317
- export async function sessionStart(session, dir, head, allSessions) {
373
+ export async function sessionStart(session, dir, head, allSessions,
374
+ /** `dry`: only whether it can start — nothing fetched or moved. For the checks before the browser opens. */
375
+ opts = {}) {
318
376
  const how = session.vcs?.startFrom ?? 'head';
319
377
  const baseBranch = session.vcs?.baseBranch?.trim() || 'main';
320
378
  if (how === 'head')
321
379
  return head ? { start: { kind: 'head', commit: head } } : {};
322
380
  const fromBranch = async (note) => {
323
381
  // The code as it is on the server, not as this checkout last pulled it: see `updateFromRemote`.
324
- const update = session.vcs?.updateFromRemote !== false && (await branchTip(dir, baseBranch)) ? await updateFromRemote(dir, baseBranch) : undefined;
382
+ const update = !opts.dry && session.vcs?.updateFromRemote !== false && (await branchTip(dir, baseBranch)) ? await updateFromRemote(dir, baseBranch) : undefined;
325
383
  const tip = await branchTip(dir, baseBranch);
326
384
  if (!tip) {
327
385
  return {
@@ -467,7 +525,9 @@ function normalise(dir) {
467
525
  }
468
526
  /** One line for the log and the event stream: where this session starts, and why. */
469
527
  export function describeStart(start) {
470
- const at = start.commit.slice(0, 8);
528
+ // With input files carried in, the start is a commit on top of the branch, not its tip: said apart (live run 2026-10-03).
529
+ const carried = start.inputs?.carried;
530
+ const at = carried ? carried.onto.slice(0, 8) : start.commit.slice(0, 8);
471
531
  const said = start.kind === 'snapshot'
472
532
  ? `this session starts from a snapshot of your uncommitted changes: ${start.branch} (${at}), taken on ${start.snapshot?.fromBranch ?? 'a detached HEAD'} at ${(start.snapshot?.fromCommit ?? '').slice(0, 8)}`
473
533
  : start.kind === 'previous-session'
@@ -478,7 +538,31 @@ export function describeStart(start) {
478
538
  ? `this session starts from the local branch ${start.branch} (${at})`
479
539
  : `this session starts from where the repository was (${at})`;
480
540
  const updated = start.update ? ` (${describeUpdate(start.update)})` : '';
481
- return start.note ? `${said}${updated} — ${start.note}` : `${said}${updated}`;
541
+ const plus = carried ? `, plus the operator's input files carried from ${carried.from} as ${start.commit.slice(0, 8)} on ${carried.branch}` : '';
542
+ return start.note ? `${said}${plus}${updated} — ${start.note}` : `${said}${plus}${updated}`;
543
+ }
544
+ /**
545
+ * Where a session leaves the repository, when its input files exist only on the runner's branches: the
546
+ * operator's base branch does not have them, and checking it out takes them out of the folder (live run
547
+ * 2026-10-03: specs/ gone after `git checkout main`, an ignored local file with it). Null when there is
548
+ * nothing to say.
549
+ */
550
+ export async function whereLeft(session) {
551
+ const files = session.vcsStart?.inputs?.files ?? [];
552
+ const dir = repoDirOf(session);
553
+ if (!session.vcs?.enabled || files.length === 0 || !dir)
554
+ return null;
555
+ const base = session.vcs.baseBranch?.trim() || 'main';
556
+ const state = await repoState(dir).catch(() => null);
557
+ if (!state?.isRepo || !state.branch || state.branch === base)
558
+ return null;
559
+ const onBase = await git(dir, ['cat-file', '-e', `refs/heads/${base}:${files[0].path}`]);
560
+ if (onBase.ok)
561
+ return null;
562
+ const paths = files.map((f) => f.path);
563
+ const list = paths.slice(0, 5).join(', ') + (paths.length > 5 ? ` and ${paths.length - 5} more` : '');
564
+ return (`the repository is left on ${state.branch}. The input files (${list}) are committed only on the runner's branches, not on ${base}: ` +
565
+ `checking out ${base} takes them out of the folder. To have them back there: git restore --source ${state.branch} -- ${paths.slice(0, 5).join(' ')}`);
482
566
  }
483
567
  /** One line for the log: the session's input files, and whether the runner had to commit them on its start. */
484
568
  export function describeInputs(start) {
@@ -529,16 +613,24 @@ opts) {
529
613
  const state = await repoState(dir);
530
614
  let name = wantedName;
531
615
  let result;
616
+ /** Whether the branch was made now, or an existing one carried on: said differently, since they are different. */
617
+ let created = false;
532
618
  if (opts.reuseExisting && state.branch === wantedName) {
533
619
  result = { ok: true, stdout: '', stderr: '', code: 0 };
534
620
  }
535
621
  else if (opts.reuseExisting) {
536
622
  const existing = await checkoutExisting(dir, wantedName);
537
- result = existing.ok || opts.mustExist ? existing : await createBranch(dir, wantedName, from);
623
+ if (existing.ok || opts.mustExist)
624
+ result = existing;
625
+ else {
626
+ result = await createBranch(dir, wantedName, from);
627
+ created = result.ok;
628
+ }
538
629
  }
539
630
  else {
540
631
  name = await freeBranchName(dir, wantedName);
541
632
  result = await createBranch(dir, name, from);
633
+ created = result.ok;
542
634
  }
543
635
  if (!result.ok) {
544
636
  // The operator's checkout as it was: the staged inputs go back to untracked.
@@ -551,8 +643,15 @@ opts) {
551
643
  }
552
644
  const after = await repoState(dir);
553
645
  const vcs = { branch: after.branch ?? name, baseCommit: after.head ?? from };
646
+ /*
647
+ * "(from X)" only for a branch made now: a branch carried on was not made from the session's base, and
648
+ * saying so sent the reader to the wrong commit (live run 2026-10-03).
649
+ */
554
650
  bus.publish({ sessionId: session.id, taskId: task.id, type: 'vcs-branch', level: 'info',
555
- message: `working on branch ${vcs.branch}${from ? ` (from ${from.slice(0, 8)})` : ''}`, data: { ...vcs, repoDir: dir } });
651
+ message: created
652
+ ? `working on branch ${vcs.branch}${from ? ` (made from ${from.slice(0, 8)})` : ''}`
653
+ : `carrying on the existing branch ${vcs.branch} at ${(vcs.baseCommit ?? '').slice(0, 8)}`,
654
+ data: { ...vcs, repoDir: dir, created } });
556
655
  // What the task stands on, and what it does not: the base commit by name, and the other
557
656
  // tasks of this session that already ran, with the branch each of them worked on.
558
657
  const subject = vcs.baseCommit ? await commitSubject(dir, vcs.baseCommit) : '';
@@ -570,6 +669,9 @@ opts) {
570
669
  earlier,
571
670
  start: opts.start,
572
671
  artifacts: artifactPatterns(session.vcs),
672
+ commits: session.vcs?.commitOnFinish !== false,
673
+ readOnly: !!task.readOnly,
674
+ created,
573
675
  });
574
676
  return { vcs, note };
575
677
  }
@@ -601,7 +703,9 @@ export function noteFor(repoDir, vcs, ctx = { mode: 'per-task', earlier: [] }) {
601
703
  : ctx.earlier.length > 0
602
704
  ? `Every task of this session gets its own branch from that same commit, so the work of the earlier tasks is NOT in your working tree: ` +
603
705
  `${ctx.earlier.map((e) => `"${e.title}" is on \`${e.branch}\``).join(', ')}. If this task depends on what one of them produced, say so in the summary rather than looking for files that are not here.`
604
- : 'Every task of this session gets its own branch from that same commit.';
706
+ : ctx.created === false
707
+ ? 'This branch is carried on, not new: the other tasks of this session get branches of their own from where the session started.'
708
+ : 'Every task of this session gets its own branch from that same commit.';
605
709
  /*
606
710
  * Where the session began, said when it was chosen. A session that continues another has that
607
711
  * session's files in its tree, and a model not told so reads them as something to redo or
@@ -619,8 +723,12 @@ export function noteFor(repoDir, vcs, ctx = { mode: 'per-task', earlier: [] }) {
619
723
  return [
620
724
  '## Version control',
621
725
  '',
622
- `The runner has already put ${repoDir} on the branch \`${vcs.branch}\`, created for this task from ${base},`,
623
- 'and it will commit whatever you change when the task finishes.',
726
+ ctx.created === false
727
+ ? `The runner has already put ${repoDir} on the existing branch \`${vcs.branch}\`, carried on at ${base} with the work already on it,`
728
+ : `The runner has already put ${repoDir} on the branch \`${vcs.branch}\`, created for this task from ${base},`,
729
+ ctx.commits === false
730
+ ? 'and it commits nothing when the task finishes: commits are off for this session, so your changes stay in the working tree, where the next task sees them.'
731
+ : 'and it will commit whatever you change when the task finishes.',
624
732
  '',
625
733
  /*
626
734
  * Said outright because a plan's text may still name the branch the work came from: a task that
@@ -647,8 +755,14 @@ export function noteFor(repoDir, vcs, ctx = { mode: 'per-task', earlier: [] }) {
647
755
  ' expects.',
648
756
  '- Do not push anything. Pushing is the operator\'s decision, made by hand, afterwards.',
649
757
  '- Read-only git is fine: `git status`, `git diff`, `git log` tell you where you are.',
650
- '- Change files as the task requires. You do not need to preserve the old ones by copying',
651
- ' them aside: the previous state is already a commit, and it can be returned to.',
758
+ ...(ctx.readOnly
759
+ ? ['- This task is read-only: change no file in the project (see "Read-only task").']
760
+ : ctx.commits === false
761
+ ? ['- Change files as the task requires. Nothing is committed for you, so think before you overwrite: the previous state is the commit above.']
762
+ : [
763
+ '- Change files as the task requires. You do not need to preserve the old ones by copying',
764
+ ' them aside: the previous state is already a commit, and it can be returned to.',
765
+ ]),
652
766
  ].join('\n');
653
767
  }
654
768
  /**
@@ -682,13 +796,14 @@ export async function commitTaskResult(session, task, outcome, bus) {
682
796
  * ("nothing committed, the tree is dirty") were written before this runs; without both states
683
797
  * the export read as contradicting itself. See `TaskVcs.beforeCommit`.
684
798
  */
685
- const beforeCommit = { changed: state.changed.slice(0, 200) };
799
+ // File by file (`git status -uall`), not the folded folders `repoState` keeps, capped at 40 (live run 2026-10-03).
800
+ const beforeCommit = { changed: (await workingTreePaths(dir)).slice(0, 200) };
686
801
  const withStates = async (v) => {
687
802
  const after = await repoState(dir).catch(() => null);
688
803
  return {
689
804
  ...v,
690
805
  beforeCommit,
691
- ...(after ? { afterCommit: { branch: after.branch ?? undefined, head: after.head ?? undefined, clean: !after.dirty, changed: after.changed.slice(0, 200) } } : {}),
806
+ ...(after ? { afterCommit: { branch: after.branch ?? undefined, head: after.head ?? undefined, clean: !after.dirty, changed: (after.dirty ? await workingTreePaths(dir) : []).slice(0, 200) } } : {}),
692
807
  };
693
808
  };
694
809
  if (state.branch !== current.branch) {
@@ -902,13 +1017,37 @@ export async function restorePreview(session, task) {
902
1017
  };
903
1018
  }
904
1019
  const prefix = session.vcs.branchPrefix || 'cop/';
1020
+ /*
1021
+ * What the restore leaves behind is measured on the line of work the task is on, not on whatever is
1022
+ * checked out: measured from HEAD it listed the operator's own unrelated commits and left out the
1023
+ * task's own work (live run 2026-10-03). Only commits that descend from the starting point count.
1024
+ */
1025
+ /*
1026
+ * In per-session mode the line is the session's branch as it is now, which `restorePoint` already
1027
+ * follows: after a "Run again from here" moved the session, the task's last attempt is on the branch it
1028
+ * left, and measured there the preview named that branch as keeping the work, listed its commits and
1029
+ * left out the ones made since on the new one (live run 2026-10-04).
1030
+ */
1031
+ const candidates = [
1032
+ ...(session.vcs.branchMode === 'per-session' && session.vcs.startFrom !== 'existing-branch' ? [sessionBranchName(session)] : []),
1033
+ ...(task.vcs?.branch ? [task.vcs.branch] : []),
1034
+ ];
1035
+ let workBranch;
1036
+ for (const b of candidates) {
1037
+ if ((await branchExists(repoDir, b)) && (await isAncestor(repoDir, base, b))) {
1038
+ workBranch = b;
1039
+ break;
1040
+ }
1041
+ }
1042
+ const line = workBranch ?? 'HEAD';
1043
+ const descends = await isAncestor(repoDir, base, line);
905
1044
  return {
906
1045
  ok: true,
907
1046
  repoDir,
908
1047
  baseCommit: base,
909
1048
  currentBranch: state.branch ?? undefined,
910
- leftBehind: await commitsBetween(repoDir, base, 'HEAD'),
911
- keptOn: state.branch ?? undefined,
1049
+ leftBehind: descends ? await commitsBetween(repoDir, base, line) : [],
1050
+ keptOn: workBranch ?? state.branch ?? undefined,
912
1051
  /*
913
1052
  * Derived from the title, so built the way every derived name is. A title is a label for the
914
1053
  * list, not a branch name anybody chose: put through `plannedBranchName`, a "/" in it ("Add
@@ -980,10 +1119,10 @@ export async function vcsPreflight(session, allSessions = async () => []) {
980
1119
  branch: state.branch ?? undefined,
981
1120
  problem: snapshot.recapture
982
1121
  ? snapshot.ok
983
- ? `Input files changed or were added since the session started (${someOf(listed, 3)}). They are committed on its line of work ${snapshot.requireApproval ? 'once you approve the list below' : 'when its next task starts'}.`
1122
+ ? `Input files changed or were added since the session started (${someOf(listed, 3)}). They are committed on its line of work ${snapshot.requireApproval ? 'once the list is approved under "Prepare version control for this run" or on the session\'s page' : 'when its next task starts'}.`
984
1123
  : `Input files changed since the session started, and they cannot be taken: ${snapshot.problem}`
985
1124
  : snapshot.ok
986
- ? `There are uncommitted changes (${someOf(listed, 3)}). They become the session's starting snapshot ${snapshot.requireApproval ? 'once you approve the list below' : 'when its first task starts'}.`
1125
+ ? `There are uncommitted changes (${someOf(listed, 3)}). They become the session's starting snapshot ${snapshot.requireApproval ? 'once the list is approved under "Prepare version control for this run" or on the session\'s page' : 'when its first task starts'}.`
987
1126
  : `There are uncommitted changes, and no starting snapshot can be taken: ${snapshot.problem}`,
988
1127
  snapshot,
989
1128
  };
@@ -997,5 +1136,15 @@ export async function vcsPreflight(session, allSessions = async () => []) {
997
1136
  problem: `There are uncommitted changes (${changed.slice(0, 3).join(', ')}${changed.length > 3 ? '…' : ''}). Commit or stash them first.`,
998
1137
  };
999
1138
  }
1139
+ /*
1140
+ * A session that continues the one before it: whether that one finished and its work is there, asked
1141
+ * here too, without fetching or moving anything. Found only when the first task was prepared, the
1142
+ * refusal came after `task-started` and the model picker and used up an attempt (live run 2026-10-03).
1143
+ */
1144
+ if (!session.vcsBaseCommit && settings.startFrom === 'previous-session') {
1145
+ const planned = await sessionStart(session, repoDir, state.head, allSessions, { dry: true });
1146
+ if ('problem' in planned)
1147
+ return { ok: false, repoDir, branch: state.branch ?? undefined, problem: planned.problem };
1148
+ }
1000
1149
  return { ok: true, repoDir, branch: state.branch ?? undefined };
1001
1150
  }
package/dist/web/404.html CHANGED
@@ -1,4 +1,4 @@
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>
1
+ <!DOCTYPE html><!--beP1HgHJZvBVRTsoU1sZv--><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-52e371cb1ec49089.js" async=""></script><script src="/_next/static/chunks/549-7e35e4fdefadb05d.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,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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>
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,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;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-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"AppearanceProvider\"]\n3:I[867,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"LanguageProvider\"]\n4:I[1035,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"DialogHost\"]\n5:I[8214,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"SkipLink\"]\n6:I[8197,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"\"]\n7:I[8214,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.js\",\"177\",\"static/chunks/app/layout-3efbb282292ccc38.js\"],\"Nav\"]\n8:I[6657,[\"197\",\"static/chunks/197-f7c33a0114fc3db3.js\",\"867\",\"static/chunks/867-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.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-52e371cb1ec49089.js\",\"549\",\"static/chunks/549-7e35e4fdefadb05d.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\":\"beP1HgHJZvBVRTsoU1sZv\",\"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:function(t){let e=!(arguments.length>1)||void 0===arguments[1]||arguments[1];return m("/repo/prepare/preview",{method:"POST",body:JSON.stringify({dir:t,fetch:e})},{timeoutMs:33e4})},prepareProject:function(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return m("/repo/prepare",{method:"POST",body:JSON.stringify({dir:t,fingerprint:e,...o})})},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")}}}]);