copilot-operator 0.1.32 → 0.1.33
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.service.js +10 -2
- package/dist/src/orchestrator/taskRunner.js +24 -14
- package/dist/src/plan/importPlan.js +5 -0
- package/dist/src/plan/systemGuide.js +8 -0
- package/dist/src/transport/copilotTransport.js +70 -36
- package/dist/src/transport/locators.js +11 -0
- package/dist/web/404.html +2 -2
- package/dist/web/_next/static/chunks/867-dfaaa8047cbf2fc2.js +1 -0
- package/dist/web/_next/static/chunks/app/defaults/page-54f8f1ab4cac47fa.js +1 -0
- package/dist/web/_next/static/chunks/app/sessions/view/page-ce99494b1997ee25.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 +2 -1
- package/dist/web/_next/static/chunks/867-52e371cb1ec49089.js +0 -1
- package/dist/web/_next/static/chunks/app/defaults/page-17dd586d1d6bd068.js +0 -1
- package/dist/web/_next/static/chunks/app/sessions/view/page-54ab3cb89b84679d.js +0 -1
- /package/dist/web/_next/static/{_Or9hW0soHRVNEEgEqiGt → G_-u_mF-aLMdcOv0kc9us}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{_Or9hW0soHRVNEEgEqiGt → G_-u_mF-aLMdcOv0kc9us}/_ssgManifest.js +0 -0
|
@@ -398,8 +398,11 @@ let OperatorService = class OperatorService {
|
|
|
398
398
|
if (patch.onFailure === 'stop' || patch.onFailure === 'continue')
|
|
399
399
|
s.onFailure = patch.onFailure;
|
|
400
400
|
// An empty string is a real choice here: it means "leave the chat on whatever it is".
|
|
401
|
-
if (patch.model !== undefined)
|
|
401
|
+
if (patch.model !== undefined) {
|
|
402
402
|
s.model = patch.model.trim() || undefined;
|
|
403
|
+
// Chosen on the session's page: the operator's own word, which outranks Settings.
|
|
404
|
+
s.modelSource = s.model ? 'operator' : undefined;
|
|
405
|
+
}
|
|
403
406
|
// The same for the group: clearing it gives this session its conversation back. It does
|
|
404
407
|
// not move the conversation it is already in; that history is where it is.
|
|
405
408
|
if (patch.conversationGroup !== undefined)
|
|
@@ -408,6 +411,8 @@ let OperatorService = class OperatorService {
|
|
|
408
411
|
// Empty model means "the session's own", which is a real choice and not a missing one.
|
|
409
412
|
const merged = { ...DEFAULT_REVIEW, ...s.review, ...patch.review };
|
|
410
413
|
s.review = { enabled: merged.enabled !== false, model: (merged.model ?? '').trim() };
|
|
414
|
+
if (patch.review.model !== undefined)
|
|
415
|
+
s.reviewModelSource = s.review.model ? 'operator' : undefined;
|
|
411
416
|
}
|
|
412
417
|
if (patch.projectDir !== undefined)
|
|
413
418
|
s.projectDir = patch.projectDir.trim();
|
|
@@ -1339,13 +1344,16 @@ let OperatorService = class OperatorService {
|
|
|
1339
1344
|
if (entry.state !== 'waiting')
|
|
1340
1345
|
continue;
|
|
1341
1346
|
await this.store.updateSession(entry.sessionId, (s) => {
|
|
1342
|
-
if (wantedModel && (s.model?.trim() || wantedModel !== followModel))
|
|
1347
|
+
if (wantedModel && (s.model?.trim() || wantedModel !== followModel)) {
|
|
1343
1348
|
s.model = wantedModel;
|
|
1349
|
+
s.modelSource = 'operator';
|
|
1350
|
+
}
|
|
1344
1351
|
// Only the model is set here, never whether the review happens: a run panel is about
|
|
1345
1352
|
// this run, and silently switching a session's review on or off from it would be a
|
|
1346
1353
|
// change to the session that outlives the run.
|
|
1347
1354
|
if (wantedReviewModel && (s.review?.model?.trim() || wantedReviewModel !== followReview)) {
|
|
1348
1355
|
s.review = { ...DEFAULT_REVIEW, ...s.review, model: wantedReviewModel };
|
|
1356
|
+
s.reviewModelSource = 'operator';
|
|
1349
1357
|
}
|
|
1350
1358
|
});
|
|
1351
1359
|
}
|
|
@@ -60,12 +60,13 @@ export const NOT_THE_CHATS = ['contract-conflict', 'environment', 'invalid-check
|
|
|
60
60
|
* Records a model the page offers under a new name where it was chosen — the session, or Settings — and
|
|
61
61
|
* the line-up read on the way. Returns the sentence that says so, or ''.
|
|
62
62
|
*/
|
|
63
|
-
async function followPageModels(which, wanted, result, session, store, hooks) {
|
|
63
|
+
async function followPageModels(which, wanted, result, session, store, hooks, from) {
|
|
64
64
|
if (result.options?.length)
|
|
65
65
|
await hooks?.seen?.(result.options, result.current).catch(() => undefined);
|
|
66
66
|
if (!result.ok || !result.matched)
|
|
67
67
|
return '';
|
|
68
|
-
|
|
68
|
+
// Written back where it came from: Settings for a model from Settings, the session for the rest.
|
|
69
|
+
const own = from !== 'settings';
|
|
69
70
|
if (own) {
|
|
70
71
|
await store
|
|
71
72
|
?.updateSession(session.id, (s) => {
|
|
@@ -514,14 +515,23 @@ export async function openSessionTransport(cfg, session, bus, runsDir) {
|
|
|
514
515
|
* A session gets a model of its own from the plan or from its own picker; one that has none
|
|
515
516
|
* follows Settings, so a model chosen there after the session was made still reaches it.
|
|
516
517
|
*/
|
|
518
|
+
/**
|
|
519
|
+
* The models a session runs on, and where each came from.
|
|
520
|
+
*
|
|
521
|
+
* The operator's choice on the session's page or the run panel first; then Settings; the plan's last.
|
|
522
|
+
* Settings used to come after any model the session held, and a plan imported with a "model" — written
|
|
523
|
+
* by another chat, often a model the picker no longer had — overrode what the operator chose in Settings
|
|
524
|
+
* on every run (operator's rule, 2026-10-06: what is set in Settings outranks the same thing in the JSON).
|
|
525
|
+
*/
|
|
517
526
|
export function effectiveModels(session, cfg) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
};
|
|
527
|
+
const pick = (own, source, settings) => own && source === 'operator' ? [own, 'session'] : settings ? [settings, 'settings'] : own ? [own, 'plan'] : ['', 'none'];
|
|
528
|
+
const [model, modelFrom] = pick((session.model ?? '').trim(), session.modelSource, (cfg.copilot.defaultModel ?? '').trim());
|
|
529
|
+
const [reviewModel, reviewModelFrom] = pick((session.review?.model ?? '').trim(), session.reviewModelSource, (cfg.copilot.defaultReviewModel ?? '').trim());
|
|
530
|
+
return { model, reviewModel, modelFrom, reviewModelFrom };
|
|
522
531
|
}
|
|
523
532
|
async function applySessionModel(transport, session, bus, cfg, store, hooks) {
|
|
524
|
-
const wanted = effectiveModels(session, cfg)
|
|
533
|
+
const { model: wanted, modelFrom } = effectiveModels(session, cfg);
|
|
534
|
+
const fromSettings = modelFrom === 'settings';
|
|
525
535
|
if (!wanted)
|
|
526
536
|
return {};
|
|
527
537
|
const locator = await hooks?.locate?.(wanted).catch(() => undefined);
|
|
@@ -530,7 +540,7 @@ async function applySessionModel(transport, session, bus, cfg, store, hooks) {
|
|
|
530
540
|
current: null,
|
|
531
541
|
reason: e.message,
|
|
532
542
|
}));
|
|
533
|
-
const renamed = await followPageModels('model', wanted, result, session, store, hooks);
|
|
543
|
+
const renamed = await followPageModels('model', wanted, result, session, store, hooks, modelFrom);
|
|
534
544
|
if (renamed)
|
|
535
545
|
bus.publish({ sessionId: session.id, type: 'model-renamed', level: 'warn', message: renamed, data: { asked: wanted, chosen: result.matched } });
|
|
536
546
|
bus.publish({
|
|
@@ -538,9 +548,9 @@ async function applySessionModel(transport, session, bus, cfg, store, hooks) {
|
|
|
538
548
|
type: result.ok ? 'model-selected' : 'model-not-selected',
|
|
539
549
|
level: result.ok ? 'info' : 'warn',
|
|
540
550
|
message: result.ok
|
|
541
|
-
? `model: ${result.current ?? wanted}${
|
|
542
|
-
: `could not switch to "${wanted}"${
|
|
543
|
-
data: { asked: wanted,
|
|
551
|
+
? `model: ${result.current ?? wanted} (${modelFrom === 'settings' ? 'from Settings' : modelFrom === 'session' ? "the session's own" : 'from the plan'})`
|
|
552
|
+
: `could not switch to "${wanted}" (${modelFrom === 'settings' ? 'the default model in Settings' : modelFrom === 'session' ? "the session's own" : 'from the plan'}): ${(result.reason ?? 'unknown reason').replace(/[.\s]+$/, '')}. Nothing is sent on ${result.current ?? 'the chat default'} instead.`,
|
|
553
|
+
data: { asked: wanted, from: modelFrom, fromSettings, current: result.current, ok: result.ok, by: result.by ?? null, savedLocator: !!locator },
|
|
544
554
|
});
|
|
545
555
|
// Kept on the session, so each task's record says which model it ran on and why (see `runTask`).
|
|
546
556
|
await store
|
|
@@ -549,7 +559,7 @@ async function applySessionModel(transport, session, bus, cfg, store, hooks) {
|
|
|
549
559
|
asked: wanted,
|
|
550
560
|
current: result.current ?? null,
|
|
551
561
|
ok: result.ok,
|
|
552
|
-
fromSettings
|
|
562
|
+
fromSettings,
|
|
553
563
|
...(result.matched ? { renamedTo: result.matched } : {}),
|
|
554
564
|
...(result.ok ? {} : { reason: (result.reason ?? 'unknown reason').replace(/[.\s]+$/, '') }),
|
|
555
565
|
at: new Date().toISOString(),
|
|
@@ -563,7 +573,7 @@ async function applySessionModel(transport, session, bus, cfg, store, hooks) {
|
|
|
563
573
|
if (!result.ok) {
|
|
564
574
|
return {
|
|
565
575
|
current: result.current ?? undefined,
|
|
566
|
-
refused: `The chat could not be put on the chosen model "${wanted}"${
|
|
576
|
+
refused: `The chat could not be put on the chosen model "${wanted}"${fromSettings ? ' (Settings)' : ''}: ${(result.reason ?? 'unknown reason').replace(/[.\s]+$/, '')}. ` +
|
|
567
577
|
'Nothing was sent. Read the list again under Settings → Model, choose the model there, and start again.',
|
|
568
578
|
};
|
|
569
579
|
}
|
|
@@ -1748,7 +1758,7 @@ export async function runTask(transport, session, task, deps) {
|
|
|
1748
1758
|
if (model) {
|
|
1749
1759
|
const reviewLocator = await deps.models?.locate?.(model).catch(() => undefined);
|
|
1750
1760
|
const picked = await transport.selectModel(model, { locator: reviewLocator }).catch((e) => ({ ok: false, current: null, reason: e.message }));
|
|
1751
|
-
const renamed = await followPageModels('review', model, picked, session, store, deps.models);
|
|
1761
|
+
const renamed = await followPageModels('review', model, picked, session, store, deps.models, effectiveModels(session, cfg).reviewModelFrom);
|
|
1752
1762
|
if (renamed)
|
|
1753
1763
|
sink.event('model-renamed', { asked: model, chosen: picked.matched, review: true }, renamed, 'warn');
|
|
1754
1764
|
sink.event(picked.ok ? 'review-model-selected' : 'review-model-not-selected', { asked: model, current: picked.current }, picked.ok ? `the review runs on ${picked.current ?? model}` : `the review could not switch to "${model}": ${picked.reason ?? 'unknown reason'}`, picked.ok ? 'info' : 'warn');
|
|
@@ -232,6 +232,11 @@ defaultProjectDir = '') {
|
|
|
232
232
|
s.review = { enabled: planned.review?.enabled !== false, model: (planned.review?.model || defaultReviewModel).trim() };
|
|
233
233
|
s.conversationGroup = group || undefined;
|
|
234
234
|
s.model = (planned.model || defaultModel).trim() || undefined;
|
|
235
|
+
// The plan's models are kept, and marked as the plan's: Settings outrank them (see `effectiveModels`).
|
|
236
|
+
if (planned.model?.trim())
|
|
237
|
+
s.modelSource = 'plan';
|
|
238
|
+
if (planned.review?.model?.trim())
|
|
239
|
+
s.reviewModelSource = 'plan';
|
|
235
240
|
s.planName = plan.plan.trim() || undefined;
|
|
236
241
|
s.vcs = vcs;
|
|
237
242
|
// After the plan's own folders are in place, so only a session that named none is pointed at it.
|
|
@@ -3004,6 +3004,14 @@ export const SYSTEM_GUIDE = [
|
|
|
3004
3004
|
doesEn: 'How many different approaches a "blocked" must list (2–20); with fewer the chat is asked for another.',
|
|
3005
3005
|
doesBg: 'Колко различни подхода трябва да изброи „blocked“ (2–20); с по-малко чатът е помолен за още един.',
|
|
3006
3006
|
},
|
|
3007
|
+
{
|
|
3008
|
+
key: 'exec.maxReviewRounds',
|
|
3009
|
+
kind: 'field',
|
|
3010
|
+
en: 'Rounds of fixing after a failed review',
|
|
3011
|
+
bg: 'Кръгове поправка след неуспешен преглед',
|
|
3012
|
+
doesEn: 'How many times a failed review sends its findings back to be fixed and reviewed again (1–6) before the task ends blocked; separate from the approaches above.',
|
|
3013
|
+
doesBg: 'Колко пъти неуспешен преглед връща находките за поправка и нов преглед (1–6), преди задачата да завърши „blocked“; отделно от подходите по-горе.',
|
|
3014
|
+
},
|
|
3007
3015
|
{
|
|
3008
3016
|
key: 'exec.retryBlocked',
|
|
3009
3017
|
kind: 'field',
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
* 2. Enter does not submit the composer. The Send button has to be clicked.
|
|
11
11
|
* 3. A message cannot consist of an attachment alone; Send stays disabled without text.
|
|
12
12
|
*/
|
|
13
|
-
import { normModel, pageModelFor, sameModel } from './modelMatch.js';
|
|
13
|
+
import { buttonShows, normModel, pageModelFor, sameModel } from './modelMatch.js';
|
|
14
14
|
import { chromium } from 'playwright';
|
|
15
15
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { findRecentCrash, describeCrash } from './edgeCrash.js';
|
|
18
18
|
import { landed } from './acceptance.js';
|
|
19
|
-
import { Blocker, Css, Label, Model, OperatorModelLocators, Rename, Sidebar, Signal, Surface, TestId, Upload, Url } from './locators.js';
|
|
19
|
+
import { Blocker, Css, Label, Model, ModelPicking, OperatorModelLocators, Rename, Sidebar, Signal, Surface, TestId, Upload, Url } from './locators.js';
|
|
20
20
|
import { acquireProfileLock } from './profileLock.js';
|
|
21
21
|
import { parseChatId } from './chatSession.js';
|
|
22
22
|
/**
|
|
@@ -938,17 +938,23 @@ Current URL: ${url}`);
|
|
|
938
938
|
async chooseByOperatorLocators(name, target) {
|
|
939
939
|
const before = await this.currentModel();
|
|
940
940
|
const textOf = async (el) => (((await el.innerText().catch(() => '')) ?? '').split('\n')[0] ?? '').trim();
|
|
941
|
+
// A fixed pause after every opening and every press (see `ModelPicking`); the checks give it less.
|
|
942
|
+
const settle = () => this.p.waitForTimeout(this.opts.modelSettleMs ?? ModelPicking.settleMs);
|
|
943
|
+
const appear = this.opts.modelAppearMs ?? ModelPicking.appearMs;
|
|
944
|
+
/** Waits until the element is there and visible. */
|
|
945
|
+
const present = async (el) => await el.waitFor({ state: 'visible', timeout: appear }).then(() => true).catch(() => false);
|
|
941
946
|
const reach = async () => {
|
|
942
947
|
const button = await this.resolveModelButton();
|
|
943
948
|
if (!button)
|
|
944
949
|
return { problem: 'This chat does not show a model picker.' };
|
|
945
950
|
await button.click();
|
|
951
|
+
await settle();
|
|
946
952
|
if (!(await this.waitForPopup()))
|
|
947
953
|
return { problem: 'The model picker did not open.' };
|
|
948
954
|
this.emit('model-step', { step: 'picker opened' });
|
|
949
955
|
if (target.group) {
|
|
950
|
-
const group = await this.rowByXPath(target.group.xpath, target.group.name,
|
|
951
|
-
if (!group)
|
|
956
|
+
const group = await this.rowByXPath(target.group.xpath, target.group.name, appear);
|
|
957
|
+
if (!group || !(await present(group)))
|
|
952
958
|
return { problem: `the "${target.group.name}" row was not found by ${target.group.xpath}` };
|
|
953
959
|
this.emit('model-step', { step: 'group found', text: await textOf(group) });
|
|
954
960
|
/*
|
|
@@ -965,8 +971,9 @@ Current URL: ${url}`);
|
|
|
965
971
|
];
|
|
966
972
|
for (const [how, act] of ways) {
|
|
967
973
|
await act().catch(() => undefined);
|
|
968
|
-
|
|
969
|
-
|
|
974
|
+
await settle();
|
|
975
|
+
const row = await this.rowByXPath(target.xpath, target.model, appear);
|
|
976
|
+
if (row && (await present(row))) {
|
|
970
977
|
this.emit('model-step', { step: 'group opened', how, model: await textOf(row) });
|
|
971
978
|
return { row };
|
|
972
979
|
}
|
|
@@ -975,45 +982,59 @@ Current URL: ${url}`);
|
|
|
975
982
|
await this.captureMenu('select-failed', await this.readMenuRows().catch(() => [])).catch(() => undefined);
|
|
976
983
|
return { problem: `"${target.model}" did not appear after opening "${target.group.name}" every way (${target.xpath}); the menu is kept as models-select-failed.html/.png` };
|
|
977
984
|
}
|
|
978
|
-
const row = await this.rowByXPath(target.xpath, target.model,
|
|
979
|
-
if (!row) {
|
|
985
|
+
const row = await this.rowByXPath(target.xpath, target.model, appear);
|
|
986
|
+
if (!row || !(await present(row))) {
|
|
980
987
|
await this.captureMenu('select-failed', await this.readMenuRows().catch(() => [])).catch(() => undefined);
|
|
981
988
|
return { problem: `"${target.model}" was not found by ${target.xpath}; the menu is kept as models-select-failed.html/.png` };
|
|
982
989
|
}
|
|
983
990
|
return { row };
|
|
984
991
|
};
|
|
985
992
|
const checked = async (row) => (await row.getAttribute('aria-checked').catch(() => null)) === 'true';
|
|
986
|
-
|
|
987
|
-
|
|
993
|
+
/*
|
|
994
|
+
* The whole choice, tried again from a closed menu while the picker does not show the model as chosen,
|
|
995
|
+
* up to `ModelPicking.attempts` times (operator's request, 2026-10-06: "if it is not set, try again").
|
|
996
|
+
*/
|
|
997
|
+
const attempts = this.opts.modelAttempts ?? ModelPicking.attempts;
|
|
998
|
+
let why = '';
|
|
999
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
1000
|
+
this.emit('model-step', { step: 'attempt', attempt, of: attempts, model: name });
|
|
1001
|
+
const found = await reach();
|
|
1002
|
+
if ('problem' in found) {
|
|
1003
|
+
why = found.problem;
|
|
1004
|
+
this.emit('model-step', { step: 'not reached', attempt, why });
|
|
1005
|
+
await this.closeMenu();
|
|
1006
|
+
await settle();
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
if (await checked(found.row)) {
|
|
1010
|
+
await this.closeMenu();
|
|
1011
|
+
this.emit('model-already-selected', { model: name, buttonShows: before, by: 'operator', attempt });
|
|
1012
|
+
return { ok: true, current: name, by: 'operator' };
|
|
1013
|
+
}
|
|
1014
|
+
// On the element itself, for the same reason as the group; the mouse only when that does nothing.
|
|
1015
|
+
this.emit('model-step', { step: 'model pressed', attempt, text: await textOf(found.row) });
|
|
1016
|
+
await found.row.evaluate((el) => el.click(), undefined, { timeout: 3_000 }).catch(() => undefined);
|
|
1017
|
+
await settle();
|
|
1018
|
+
if ((await this.modelMenuOpen()) && !(await checked(found.row))) {
|
|
1019
|
+
await found.row.click({ timeout: 3_000 }).catch(() => undefined);
|
|
1020
|
+
await settle();
|
|
1021
|
+
}
|
|
988
1022
|
await this.closeMenu();
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1023
|
+
await settle();
|
|
1024
|
+
// Is it set? Read again, the same way, from a fresh menu.
|
|
1025
|
+
const again = await reach();
|
|
1026
|
+
const ok = 'row' in again && (await checked(again.row));
|
|
992
1027
|
await this.closeMenu();
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
await found.row.click({ timeout: 3_000 }).catch(() => undefined);
|
|
1002
|
-
await this.p.waitForTimeout(400);
|
|
1003
|
-
await this.closeMenu();
|
|
1004
|
-
const again = await reach();
|
|
1005
|
-
const ok = 'row' in again && (await checked(again.row));
|
|
1006
|
-
await this.closeMenu();
|
|
1007
|
-
const after = await this.currentModel();
|
|
1008
|
-
if (ok) {
|
|
1009
|
-
this.emit('model-selected', { model: name, buttonShows: after, by: 'operator' });
|
|
1010
|
-
return { ok: true, current: name, by: 'operator' };
|
|
1028
|
+
const after = await this.currentModel();
|
|
1029
|
+
if (ok) {
|
|
1030
|
+
this.emit('model-selected', { model: name, buttonShows: after, by: 'operator', attempt });
|
|
1031
|
+
return { ok: true, current: name, by: 'operator' };
|
|
1032
|
+
}
|
|
1033
|
+
why = 'problem' in again ? `after pressing "${target.model}": ${again.problem}` : `"${target.model}" was pressed, but the picker does not mark it as chosen (the button shows "${after ?? 'nothing'}")`;
|
|
1034
|
+
this.emit('model-step', { step: 'not set, trying again', attempt, why });
|
|
1035
|
+
await settle();
|
|
1011
1036
|
}
|
|
1012
|
-
return {
|
|
1013
|
-
ok: false,
|
|
1014
|
-
current: after,
|
|
1015
|
-
reason: 'problem' in again ? `after pressing "${target.model}": ${again.problem}` : `"${target.model}" was pressed, but the picker does not mark it as chosen (the button shows "${after ?? 'nothing'}").`,
|
|
1016
|
-
};
|
|
1037
|
+
return { ok: false, current: await this.currentModel(), reason: `not chosen after ${attempts} attempts: ${why}` };
|
|
1017
1038
|
}
|
|
1018
1039
|
/**
|
|
1019
1040
|
* Whether the model picker is open: its button says so (`aria-expanded`), or its rows are on screen.
|
|
@@ -1118,6 +1139,17 @@ Current URL: ${url}`);
|
|
|
1118
1139
|
const button = await this.resolveModelButton();
|
|
1119
1140
|
if (!button)
|
|
1120
1141
|
return { ok: false, current: null, reason: 'This chat does not show a model picker.' };
|
|
1142
|
+
/*
|
|
1143
|
+
* Looked at before anything is opened: a conversation the run comes back to is usually on its model
|
|
1144
|
+
* already, and choosing it again was a menu walk for nothing (operator's request, 2026-10-06). The
|
|
1145
|
+
* button shows the model, shortened by words dropped from its end ("GPT-5.6 Sol Think"), and
|
|
1146
|
+
* `buttonShows` takes only that, so "Think deeper" is never taken for "GPT-5.6 Sol Think deeper".
|
|
1147
|
+
*/
|
|
1148
|
+
const shown = await this.currentModel();
|
|
1149
|
+
if (buttonShows(shown, name)) {
|
|
1150
|
+
this.emit('model-already-selected', { model: name, buttonShows: shown, by: 'button' });
|
|
1151
|
+
return { ok: true, current: name, by: 'already' };
|
|
1152
|
+
}
|
|
1121
1153
|
// The operator's own locators first, for the models they cover (see `OperatorModelLocators`).
|
|
1122
1154
|
const target = operatorTargetFor(name);
|
|
1123
1155
|
let first = null;
|
|
@@ -1149,6 +1181,8 @@ Current URL: ${url}`);
|
|
|
1149
1181
|
const chosen = await this.chooseAt(match.name, match.locator);
|
|
1150
1182
|
return {
|
|
1151
1183
|
...chosen,
|
|
1184
|
+
// When both ways failed, why the operator's locators did is said too: that is the one to fix.
|
|
1185
|
+
...(!chosen.ok && first?.reason ? { reason: `${chosen.reason ?? 'not chosen'} (${target ? "by the operator's locators" : 'at the saved place'}: ${first.reason})` } : {}),
|
|
1152
1186
|
...(chosen.ok && !sameModel(match.name, name) ? { matched: match.name } : {}),
|
|
1153
1187
|
...(chosen.ok ? { by: opts.locator ? 'reread' : 'name' } : {}),
|
|
1154
1188
|
// Why the saved locator missed, kept: what to look at when the page has changed.
|
|
@@ -159,6 +159,17 @@ export const OperatorModelLocators = {
|
|
|
159
159
|
},
|
|
160
160
|
],
|
|
161
161
|
};
|
|
162
|
+
/**
|
|
163
|
+
* How patiently a model is chosen with those locators (operator's request, 2026-10-06): every element is
|
|
164
|
+
* waited for until it is there and visible (`appearMs`), a fixed pause follows every opening and every
|
|
165
|
+
* press (`settleMs`), and a choice the picker does not show as made is tried again from the start, up to
|
|
166
|
+
* `attempts` times, before the run is told it failed.
|
|
167
|
+
*/
|
|
168
|
+
export const ModelPicking = {
|
|
169
|
+
attempts: 6,
|
|
170
|
+
settleMs: 1_500,
|
|
171
|
+
appearMs: 10_000,
|
|
172
|
+
};
|
|
162
173
|
/** A text as an XPath string literal, whatever quotes it holds. */
|
|
163
174
|
export function xpathText(text) {
|
|
164
175
|
if (!text.includes("'"))
|
package/dist/web/404.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--G__u_mF_aLMdcOv0kc9us--><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-dfaaa8047cbf2fc2.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,"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-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\":\"_Or9hW0soHRVNEEgEqiGt\",\"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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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-dfaaa8047cbf2fc2.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\":\"G_-u_mF-aLMdcOv0kc9us\",\"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>
|