@omerrgocmen/crewctl 1.3.2 → 1.3.3
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.
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
},
|
|
47
47
|
"cliSettings": {
|
|
48
48
|
"codex": { "model": "", "reasoningEffort": "medium", "serviceTier": "fast" },
|
|
49
|
+
"claude": {
|
|
50
|
+
"_comment": "Bos model Claude Code hesap varsayilanini kullanir. Arayuz guncel modelleri tam surum kimlikleriyle sunar ve secilen degeri `claude --model <name>` olarak uygular.",
|
|
51
|
+
"model": ""
|
|
52
|
+
},
|
|
49
53
|
"opencode": {
|
|
50
54
|
"_comment": "model: acikca bir model yazarsaniz otomatik secim tumden atlanir (en guvenilir yol; `opencode models` ciktisindan bir satir). Bos birakilirsa modelPreferences desenleri sirayla denenir ve ILK eslesen kullanilir; `*` joker karakterdir. Saglayici adlari kisiden kisiye degisir (kendi aboneliginiz opencode-go, minimax, openrouter, kendi sunucunuz olabilir), bu yuzden burada saglayici adi sabitlenmez — kendi tercihinizi one almak icin listeyi duzenleyin, or. \"opencode-go/*\" en basa. modelExclude: erisilebilir varsayilmayacak saglayicilar; kendi yerel sunucunuzu kullanmak istiyorsaniz ilgili satiri silin.",
|
|
51
55
|
"model": "",
|
|
@@ -323,6 +323,10 @@ function effectiveAgent(agent, cfg) {
|
|
|
323
323
|
else copy.args.push("--output-format", "stream-json");
|
|
324
324
|
// stream-json, -p (print) modunda --verbose ZORUNLU kilar; yoksa claude hata verir.
|
|
325
325
|
if (!copy.args.includes("--verbose")) copy.args.push("--verbose");
|
|
326
|
+
// Claude Code model secimini oturum baslangicinda --model ile kabul eder. Alias kullanmak
|
|
327
|
+
// (sonnet/opus/haiku vb.) sağlayiciya gore guncel, erisilebilir surume cozumlenmesini saglar.
|
|
328
|
+
const model = String(copy.model || settings.model || "").trim();
|
|
329
|
+
if (model && !copy.args.includes("--model") && !copy.args.includes("-m")) copy.args.push("--model", model);
|
|
326
330
|
}
|
|
327
331
|
if (adapter === "gemini") {
|
|
328
332
|
// Otonom, non-interaktif calisma icin onay modu sart; yoksa izin bekleyip takilir.
|
|
@@ -745,6 +749,112 @@ function listCodexModels(options = {}) {
|
|
|
745
749
|
});
|
|
746
750
|
}
|
|
747
751
|
|
|
752
|
+
// Claude Code'un Agent SDK kontrol protokolu, oturum acilisinda o kullanicinin
|
|
753
|
+
// hesabina/saglayicisina/kurum politikasina gore gercekten secilebilir modelleri dondurur.
|
|
754
|
+
// Statik model kimlikleri tutmak hem hizla eskir hem de baska bir kullanicida gorunmeyen
|
|
755
|
+
// bir modeli secilebilir gosterir. Bu normalizer yalnizca UI'nin ihtiyaci olan alanlari
|
|
756
|
+
// alir; initialize yanitindaki hesap bilgilerini disari sizdirmaz.
|
|
757
|
+
function normalizeClaudeModels(models) {
|
|
758
|
+
const seen = new Set();
|
|
759
|
+
const normalized = [];
|
|
760
|
+
for (const model of Array.isArray(models) ? models : []) {
|
|
761
|
+
const id = String(model?.value || "").trim();
|
|
762
|
+
if (!id || seen.has(id)) continue;
|
|
763
|
+
seen.add(id);
|
|
764
|
+
normalized.push({
|
|
765
|
+
id,
|
|
766
|
+
resolvedModel: String(model.resolvedModel || "").trim(),
|
|
767
|
+
displayName: String(model.displayName || id).trim(),
|
|
768
|
+
description: String(model.description || "").trim(),
|
|
769
|
+
supportsEffort: model.supportsEffort === true,
|
|
770
|
+
supportedEffortLevels: Array.isArray(model.supportedEffortLevels)
|
|
771
|
+
? model.supportedEffortLevels.map(String).filter(Boolean)
|
|
772
|
+
: [],
|
|
773
|
+
supportsAdaptiveThinking: model.supportsAdaptiveThinking === true,
|
|
774
|
+
supportsFastMode: model.supportsFastMode === true,
|
|
775
|
+
supportsAutoMode: model.supportsAutoMode === true,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
return normalized;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function listClaudeModels(options = {}) {
|
|
782
|
+
const args = ["--output-format", "stream-json", "--verbose", "--input-format", "stream-json", "--no-session-persistence"];
|
|
783
|
+
const command = buildCommand(options.command || RESOLVED.get("claude") || DEFINITIONS.claude.command, args);
|
|
784
|
+
const timeoutMs = Math.max(5000, Number(options.timeoutMs || 20000));
|
|
785
|
+
const requestId = "crewctl-claude-models";
|
|
786
|
+
return new Promise((resolve, reject) => {
|
|
787
|
+
let buffer = "", stderr = "", settled = false;
|
|
788
|
+
let child, unregister = () => {};
|
|
789
|
+
const finish = (error, value) => {
|
|
790
|
+
if (settled) return;
|
|
791
|
+
settled = true;
|
|
792
|
+
clearTimeout(timer);
|
|
793
|
+
unregister();
|
|
794
|
+
terminateProbeTree(child);
|
|
795
|
+
if (error) reject(error); else resolve(value);
|
|
796
|
+
};
|
|
797
|
+
const timer = setTimeout(
|
|
798
|
+
() => finish(new Error(`Claude Code model listesi ${Math.round(timeoutMs / 1000)} saniyede alinamadi.`)),
|
|
799
|
+
timeoutMs,
|
|
800
|
+
);
|
|
801
|
+
try {
|
|
802
|
+
child = spawn(command.file, command.args, {
|
|
803
|
+
shell: command.shell,
|
|
804
|
+
windowsHide: true,
|
|
805
|
+
windowsVerbatimArguments: !!command.verbatim,
|
|
806
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
807
|
+
env: {
|
|
808
|
+
...process.env,
|
|
809
|
+
CLAUDE_CODE_ENTRYPOINT: "sdk-ts",
|
|
810
|
+
CLAUDE_AGENT_SDK_CLIENT_APP: "crewctl",
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
} catch (error) {
|
|
814
|
+
finish(error);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
unregister = registerProbe(child);
|
|
818
|
+
child.stdout?.setEncoding("utf8");
|
|
819
|
+
child.stderr?.setEncoding("utf8");
|
|
820
|
+
child.stdout?.on("data", (chunk) => {
|
|
821
|
+
buffer += String(chunk);
|
|
822
|
+
const lines = buffer.split(/\r?\n/);
|
|
823
|
+
buffer = lines.pop() || "";
|
|
824
|
+
for (const line of lines) {
|
|
825
|
+
let message;
|
|
826
|
+
try { message = JSON.parse(line); } catch { continue; }
|
|
827
|
+
if (message.type !== "control_response" || message.response?.request_id !== requestId) continue;
|
|
828
|
+
if (message.response?.subtype !== "success") {
|
|
829
|
+
finish(new Error(message.response?.error || "Claude Code model listesi alinamadi."));
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
const models = message.response?.response?.models;
|
|
833
|
+
if (!Array.isArray(models)) {
|
|
834
|
+
finish(new Error("Bu Claude Code surumu dinamik model katalogunu desteklemiyor."));
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
finish(null, normalizeClaudeModels(models));
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
child.stderr?.on("data", (chunk) => {
|
|
842
|
+
stderr = `${stderr}${String(chunk)}`.slice(-2048);
|
|
843
|
+
});
|
|
844
|
+
child.on("error", (error) => finish(error));
|
|
845
|
+
child.on("close", (code) => {
|
|
846
|
+
if (settled) return;
|
|
847
|
+
finish(new Error(stderr.trim() || `Claude Code model katalogu okunamadan cikti (kod ${code}).`));
|
|
848
|
+
});
|
|
849
|
+
child.stdin?.on("error", () => {});
|
|
850
|
+
child.stdin?.write(`${JSON.stringify({
|
|
851
|
+
type: "control_request",
|
|
852
|
+
request_id: requestId,
|
|
853
|
+
request: { subtype: "initialize" },
|
|
854
|
+
})}\n`);
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
|
|
748
858
|
function addMissingAgents(cfg, discovered) {
|
|
749
859
|
cfg.agents ||= {};
|
|
750
860
|
const ignored = new Set(Array.isArray(cfg.discoveryIgnoredAdapters) ? cfg.discoveryIgnoredAdapters.map(String) : []);
|
|
@@ -857,4 +967,4 @@ function ensureValidOperator(cfg, discovered) {
|
|
|
857
967
|
return changed;
|
|
858
968
|
}
|
|
859
969
|
|
|
860
|
-
module.exports = { DEFINITIONS, KNOWN_CLIS: Object.keys(DEFINITIONS), adapterId, authHint, normalizeAgentAdapter, normalizeAgentAdapters, effectiveAgent, preparePromptArgs, operatorSpec, buildCommand, agentEnvironment, discoverInstalled, discoveryCacheFrom, applyOpenCodeFallback, healthCheckAll, listCodexModels, abortActiveProbes, currentProbeGeneration, selectOpenCodeModel, parseOpenCodeModels, addMissingAgents, ensureValidOperator };
|
|
970
|
+
module.exports = { DEFINITIONS, KNOWN_CLIS: Object.keys(DEFINITIONS), adapterId, authHint, normalizeAgentAdapter, normalizeAgentAdapters, effectiveAgent, preparePromptArgs, operatorSpec, buildCommand, agentEnvironment, discoverInstalled, discoveryCacheFrom, applyOpenCodeFallback, healthCheckAll, listCodexModels, listClaudeModels, normalizeClaudeModels, abortActiveProbes, currentProbeGeneration, selectOpenCodeModel, parseOpenCodeModels, addMissingAgents, ensureValidOperator };
|
|
@@ -28,6 +28,7 @@ const HEALTH_CACHE_VERSION = 2;
|
|
|
28
28
|
const CODEX_MODEL_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
29
29
|
let codexModelRefreshDue = false;
|
|
30
30
|
let codexModelCache = { checkedAt: 0, models: [] };
|
|
31
|
+
let claudeModelCache = { checkedAt: 0, models: [] };
|
|
31
32
|
|
|
32
33
|
// OpenCode model listesini config'e yaz: prob taze (cache-disi) liste dondurdugunde saklariz
|
|
33
34
|
// ki bir sonraki acilista `opencode models` gecici olarak yavas/basarisiz olsa bile dropdown
|
|
@@ -201,6 +202,13 @@ async function getCodexModels(force = false) {
|
|
|
201
202
|
store.saveConfig(cfg);
|
|
202
203
|
return models;
|
|
203
204
|
}
|
|
205
|
+
async function getClaudeModels(force = false) {
|
|
206
|
+
if (!force && claudeModelCache.models.length && Date.now() - claudeModelCache.checkedAt < CODEX_MODEL_CACHE_TTL_MS) return claudeModelCache.models;
|
|
207
|
+
if (engineBusy()) return claudeModelCache.models;
|
|
208
|
+
const models = await cliRegistry.listClaudeModels({ timeoutMs: 20000 });
|
|
209
|
+
claudeModelCache = { checkedAt: Date.now(), models };
|
|
210
|
+
return models;
|
|
211
|
+
}
|
|
204
212
|
async function refreshCliHealth(force = false) {
|
|
205
213
|
if (healthRunning) return cliStatus;
|
|
206
214
|
const cfg = store.loadConfig();
|
|
@@ -594,6 +602,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
594
602
|
// liste gelirse persistOpenCodeModels ile guncellenir. cfg ise model onerisini
|
|
595
603
|
// kullanicinin modelPreferences desenlerine gore urettirir.
|
|
596
604
|
const cfg = store.loadConfig();
|
|
605
|
+
claudeModelCache = { checkedAt: 0, models: [] };
|
|
597
606
|
cliStatus = cliRegistry.discoverInstalled({ force: true, cfg, openCodeModels: cfg.openCodeModelCache?.models });
|
|
598
607
|
cfg.cliDiscoveryCache = cliRegistry.discoveryCacheFrom(cliStatus);
|
|
599
608
|
const body = await readBody(req);
|
|
@@ -615,6 +624,10 @@ const server = http.createServer(async (req, res) => {
|
|
|
615
624
|
try { return send(res, 200, { models: await getCodexModels(false) }); }
|
|
616
625
|
catch (error) { return send(res, 502, { error: `Codex modelleri alınamadı: ${error.message}` }); }
|
|
617
626
|
}
|
|
627
|
+
if (pathname === "/api/claude/models" && req.method === "GET") {
|
|
628
|
+
try { return send(res, 200, { models: await getClaudeModels(false) }); }
|
|
629
|
+
catch (error) { return send(res, 502, { error: `Claude Code modelleri alınamadı: ${error.message}` }); }
|
|
630
|
+
}
|
|
618
631
|
if (pathname === "/api/projects" && req.method === "GET") {
|
|
619
632
|
return send(res, 200, { projects: store.listProjects() });
|
|
620
633
|
}
|
|
@@ -759,7 +772,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
759
772
|
cliRegistry.normalizeAgentAdapters(cfg);
|
|
760
773
|
if (cfg.cliSettings.codex.reasoningEffort && !["low", "medium", "high", "xhigh", "max", "ultra"].includes(cfg.cliSettings.codex.reasoningEffort)) return send(res, 400, { error: "cliSettings.codex.reasoningEffort gecersiz" });
|
|
761
774
|
if (cfg.cliSettings.codex.serviceTier && !/^[A-Za-z0-9._-]{1,64}$/.test(cfg.cliSettings.codex.serviceTier)) return send(res, 400, { error: "cliSettings.codex.serviceTier gecersiz" });
|
|
762
|
-
for (const id of ["codex", "opencode"]) {
|
|
775
|
+
for (const id of ["codex", "claude", "opencode"]) {
|
|
763
776
|
if (cfg.cliSettings[id].model != null && typeof cfg.cliSettings[id].model !== "string") return send(res, 400, { error: `cliSettings.${id}.model metin olmali` });
|
|
764
777
|
}
|
|
765
778
|
if (cfg.skills !== undefined) {
|
|
@@ -137,6 +137,7 @@ const FALLBACK_CONFIG = {
|
|
|
137
137
|
resilience: { transientRetries: 2, retryBaseSeconds: 3, maxFailoverAgents: 1 },
|
|
138
138
|
cliSettings: {
|
|
139
139
|
codex: { model: "", reasoningEffort: "medium", serviceTier: "fast" },
|
|
140
|
+
claude: { model: "" },
|
|
140
141
|
opencode: { model: "", modelPreferences: ["*deepseek*free*", "*free*", "*"], modelExclude: ["ollama/*", "lmstudio/*", "llamacpp/*", "local/*", "localhost/*"] },
|
|
141
142
|
},
|
|
142
143
|
skills: { enabled: [], autoMatch: true, catalogLimit: 12, maxSkillsPerAssignment: 3, charBudget: 2400, referenceCharBudget: 1200 },
|
|
@@ -167,6 +168,7 @@ function normalizeConfig(cfg) {
|
|
|
167
168
|
},
|
|
168
169
|
cliSettings: {
|
|
169
170
|
codex: { model: "", reasoningEffort: "medium", serviceTier: "fast", ...legacyCodex, ...(current.codex || {}) },
|
|
171
|
+
claude: { model: "", ...(current.claude || {}) },
|
|
170
172
|
// Desenler mevcut config'lere de eklenir ki kullanici bunlari Ayarlar'da gorup
|
|
171
173
|
// kendi aboneligine gore duzenleyebilsin. Kendi degerini yazan kullanicininki korunur.
|
|
172
174
|
opencode: {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
--headerbg:#0a0f1acc;--input:#0b111c;--term:#05080f;--termtx:#c7d3e6;--nodebg:#0b1220;--glow:#5e8bff26;--shadow:0 14px 44px #0009;--appbg:radial-gradient(1200px 560px at 12% -10%,#5e8bff16,transparent),radial-gradient(1000px 520px at 92% -8%,#a98bff10,transparent),var(--bg)}
|
|
16
16
|
[data-theme=light]{--bg:#edf1f8;--panel:#ffffff;--panel2:#f3f6fc;--line:#dce4ef;--tx:#131a27;--dim:#5a6779;--acc:#3a63f0;--ok:#0ca678;--warn:#a76a10;--err:#dc434e;--purple:#7350f0;
|
|
17
17
|
--headerbg:#ffffffe6;--input:#f4f7fd;--term:#0d1420;--termtx:#c7d3e6;--nodebg:#f7f9fd;--glow:#3a63f01c;--shadow:0 14px 40px #7a90b820;--appbg:radial-gradient(1200px 560px at 12% -10%,#3a63f012,transparent),radial-gradient(1000px 520px at 92% -8%,#7350f00e,transparent),var(--bg)}
|
|
18
|
-
[data-theme=light] .team-node.operator
|
|
18
|
+
[data-theme=light] .team-node.operator{border-color:color-mix(in srgb,var(--nacc) 40%,var(--line));background:linear-gradient(150deg,color-mix(in srgb,var(--nacc) 10%,var(--panel2)),var(--nodebg) 60%)}
|
|
19
19
|
[data-theme=light] .friendly-error{background:#fdecee;color:#8f1f28;border-color:#d6404b55}[data-theme=light] .friendly-error b{color:#c02e39}[data-theme=light] .friendly-error small{color:#9a5a60}
|
|
20
20
|
[data-theme=light] .friendly-error.success{background:#e9f8f0;color:#0d5c3c;border-color:#0f9d6355}[data-theme=light] .friendly-error.success b{color:var(--ok)}[data-theme=light] .friendly-error.success small{color:#4f7d68}
|
|
21
21
|
[data-theme=light] .fi-failure,[data-theme=light] .fi-blocked{background:#fdecef}
|
|
@@ -109,20 +109,29 @@ details summary{cursor:pointer;color:var(--dim);font-size:12px} pre{white-space:
|
|
|
109
109
|
.live-details>summary{list-style:none;display:flex;align-items:center;gap:8px;font-weight:700}.live-details>summary::-webkit-details-marker{display:none}.live-details>summary:before{content:'›';font-size:18px;color:var(--dim)}.live-details[open]>summary:before{transform:rotate(90deg)}.live-details .live-body{padding-top:12px}
|
|
110
110
|
/* Ekip haritasi — operasyon dugumleri */
|
|
111
111
|
.mission-top{display:flex;align-items:center;gap:10px}
|
|
112
|
-
.mission-title{font-weight:750;font-size:15px;letter-spacing:-.15px}.mission-sub{color:var(--dim);font-size:11px}
|
|
113
|
-
|
|
114
|
-
.
|
|
115
|
-
.
|
|
116
|
-
.
|
|
117
|
-
.
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
.team-
|
|
121
|
-
.team-node
|
|
122
|
-
.
|
|
123
|
-
.
|
|
124
|
-
.team-node.
|
|
125
|
-
.
|
|
112
|
+
.mission-title{font-weight:750;font-size:15px;letter-spacing:-.15px}.mission-sub{color:var(--dim);font-size:11px;margin-top:1px}
|
|
113
|
+
/* Butunlesik takim akisi paneli — bolum basliklari */
|
|
114
|
+
.flow-seg{margin-top:16px}
|
|
115
|
+
.flow-seg-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
|
|
116
|
+
.flow-seg-head .lbl{font-size:9.5px;font-weight:800;letter-spacing:1.3px;text-transform:uppercase;color:var(--dim)}
|
|
117
|
+
.flow-seg-head .ln{flex:1;height:1px;background:linear-gradient(90deg,color-mix(in srgb,var(--line) 85%,transparent),transparent)}
|
|
118
|
+
.flow-seg-head .hint{font-size:10.5px;color:var(--dim)}
|
|
119
|
+
/* Ekip seridi — operator + uzman dugumleri yatay boru hatti cipleri */
|
|
120
|
+
.team-map{display:flex;align-items:center;gap:0;overflow-x:auto;padding:18px 10px 26px;scrollbar-width:thin}
|
|
121
|
+
.team-node{--nacc:var(--acc);position:relative;flex:none;display:flex;align-items:center;gap:13px;padding:12px 20px 12px 12px;border:1px solid color-mix(in srgb,var(--nacc) 26%,var(--line));border-radius:16px;background:linear-gradient(150deg,color-mix(in srgb,var(--nacc) 10%,var(--nodebg)),var(--nodebg) 62%);box-shadow:0 10px 26px #0004;color:var(--tx);transition:border-color .25s,box-shadow .25s,transform .2s}
|
|
122
|
+
.node-orb{position:relative;isolation:isolate;flex:none;width:54px;height:54px;display:grid;place-items:center;border:1px solid transparent;border-radius:50%;background:radial-gradient(circle at 36% 28%,color-mix(in srgb,var(--nacc) 22%,var(--nodebg)),var(--nodebg) 60%) padding-box,conic-gradient(from 210deg,var(--nacc),#38577d 40%,var(--line) 66%,var(--nacc)) border-box;box-shadow:inset 0 -7px 16px #0003,0 7px 16px #0004}
|
|
123
|
+
.node-orb:before{content:'';position:absolute;inset:-5px;border:1px dashed color-mix(in srgb,var(--nacc) 36%,transparent);border-radius:50%;opacity:0}
|
|
124
|
+
.team-node.working .node-orb:before{opacity:1;animation:nodeOrbit 9s linear infinite}
|
|
125
|
+
.node-glyph{position:relative;z-index:1;font:850 15px/1 ui-monospace,Consolas,monospace;letter-spacing:.5px;color:var(--nacc);text-shadow:0 0 11px color-mix(in srgb,var(--nacc) 60%,transparent)}
|
|
126
|
+
.node-status{position:absolute;z-index:2;right:-1px;bottom:1px;width:14px;height:14px;border:3px solid var(--nodebg);border-radius:50%;background:var(--dim)}
|
|
127
|
+
.node-info{min-width:0;text-align:left}
|
|
128
|
+
.team-node .nrole{font-size:8.5px;letter-spacing:1px;text-transform:uppercase;color:var(--dim)}
|
|
129
|
+
.team-node .nname{max-width:170px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:750;font-size:14.5px;margin-top:2px}.team-node .nstate{font-size:11.5px;color:var(--dim);margin-top:2px}
|
|
130
|
+
.team-node.operator .node-orb{background:radial-gradient(circle at 36% 28%,color-mix(in srgb,var(--nacc) 20%,var(--nodebg)),var(--nodebg) 60%) padding-box,conic-gradient(from 210deg,var(--nacc),#64449a 44%,var(--line) 68%,var(--nacc)) border-box}.team-node.operator .node-glyph{color:var(--nacc)}
|
|
131
|
+
.team-node.working{transform:translateY(-2px);border-color:color-mix(in srgb,var(--ok) 46%,var(--line));box-shadow:0 12px 30px color-mix(in srgb,var(--ok) 18%,transparent)}.team-node.working .nstate{color:var(--ok)}.team-node.working .node-status{background:var(--ok);box-shadow:0 0 9px var(--ok)}
|
|
132
|
+
.team-node.done{border-color:color-mix(in srgb,var(--acc) 38%,var(--line))}.team-node.done .node-status{background:var(--acc)}
|
|
133
|
+
.team-node.failed{border-color:color-mix(in srgb,var(--err) 48%,var(--line))}.team-node.failed .node-status{background:var(--err);box-shadow:0 0 8px var(--err)}.team-node.failed .node-orb{filter:saturate(.7)}
|
|
134
|
+
.team-link{position:relative;z-index:2;flex:none;align-self:center;height:2px;width:66px;margin:0 15px 0 -1px;background:repeating-linear-gradient(90deg,color-mix(in srgb,var(--acc) 46%,var(--line)) 0 5px,transparent 5px 12px);background-size:24px 2px;animation:teamRail 1.1s linear infinite;filter:drop-shadow(0 0 3px color-mix(in srgb,var(--acc) 20%,transparent))}.team-link:before{content:'';position:absolute;left:0;top:50%;width:6px;height:6px;border-radius:50%;background:var(--acc);box-shadow:0 0 8px var(--acc);transform:translate(-50%,-50%);opacity:0}.team-link:after{content:'';position:absolute;right:-1px;top:50%;width:6px;height:6px;border-top:2px solid var(--acc);border-right:2px solid var(--acc);transform:translateY(-50%) rotate(45deg);filter:drop-shadow(0 0 3px var(--acc))}.team-link.active{background:linear-gradient(90deg,transparent,var(--acc),transparent);box-shadow:0 0 10px color-mix(in srgb,var(--acc) 60%,transparent)}.team-link.active:before{opacity:1;animation:teamPulse 1.15s ease-in-out infinite}.team-link.active:after{border-color:var(--ok);filter:drop-shadow(0 0 4px var(--ok))}
|
|
126
135
|
@keyframes nodeOrbit{to{transform:rotate(360deg)}}@keyframes teamRail{to{background-position:24px 0}}@keyframes teamPulse{from{left:0}to{left:100%}}
|
|
127
136
|
/* Agent calisma panelleri */
|
|
128
137
|
.agent-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(330px,1fr));gap:14px}
|
|
@@ -147,23 +156,25 @@ details summary{cursor:pointer;color:var(--dim);font-size:12px} pre{white-space:
|
|
|
147
156
|
.friendly-error b{display:block;color:#ff8f97;margin-bottom:3px;overflow-wrap:anywhere}.friendly-error small{color:#d5aeb2}
|
|
148
157
|
.friendly-error.success{border-color:#42d39255;background:#10261e;color:#d7ffec}.friendly-error.success b{color:var(--ok)}.friendly-error.success small{color:#a7cfbd}
|
|
149
158
|
.plan-pills{display:flex;gap:5px;flex-wrap:wrap;margin-top:7px}.plan-pills span{font-size:10px;border:1px solid #42d39255;border-radius:999px;padding:2px 7px}
|
|
150
|
-
/* Birlesik akis —
|
|
151
|
-
.feed{max-height:
|
|
152
|
-
.feed-item{position:relative;display:flex;gap:
|
|
153
|
-
.
|
|
154
|
-
.
|
|
155
|
-
.fi-
|
|
159
|
+
/* Birlesik akis — sistem satirlari ince tek satir, mesaj/teslimat renk-kodlu belirgin kart */
|
|
160
|
+
.feed{max-height:460px;overflow:auto;display:flex;flex-direction:column;gap:6px;padding-right:2px}
|
|
161
|
+
.feed-item{position:relative;display:flex;gap:11px;padding:10px 13px;border-radius:12px;transition:background .14s,border-color .18s}
|
|
162
|
+
.fi-log{gap:9px;padding:5px 9px;border-radius:8px}
|
|
163
|
+
.fi-log:hover{background:color-mix(in srgb,var(--panel2) 50%,transparent)}
|
|
164
|
+
.fi-delegation,.fi-result,.fi-failure,.fi-blocked{border:1px solid color-mix(in srgb,var(--evc) 24%,var(--line));border-left:3px solid var(--evc);background:color-mix(in srgb,var(--evc) 6%,var(--panel2));box-shadow:0 6px 18px #00000026}
|
|
165
|
+
.fi-delegation:hover,.fi-result:hover,.fi-failure:hover,.fi-blocked:hover{border-color:color-mix(in srgb,var(--evc) 42%,var(--line));border-left-color:var(--evc)}
|
|
166
|
+
.fi-dot{position:relative;z-index:1;flex:none;margin-top:1px;width:23px;height:23px;border-radius:50%;display:grid;place-items:center;font:800 11px/1 ui-monospace,Consolas,monospace;color:var(--evc,var(--dim));border:1px solid color-mix(in srgb,var(--evc,var(--line)) 45%,var(--line));background:color-mix(in srgb,var(--evc,var(--dim)) 15%,var(--panel))}
|
|
167
|
+
.fi-log .fi-dot{width:19px;height:19px;font-size:10px}
|
|
156
168
|
.fi-main{min-width:0;flex:1}
|
|
157
|
-
.fi-head{display:flex;align-items:center;gap:
|
|
158
|
-
.fi-from{font-weight:
|
|
159
|
-
.fi-tag{font:10px ui-monospace,Consolas,monospace;color:var(--dim);border:1px solid var(--line);border-radius:
|
|
169
|
+
.fi-head{display:flex;align-items:center;gap:7px;flex-wrap:wrap;font-size:12px;line-height:1.5}
|
|
170
|
+
.fi-from{font-weight:750}.fi-arrow{color:var(--dim);opacity:.55}.fi-to{font-weight:700;color:var(--tx)}
|
|
171
|
+
.fi-tag{font:10px ui-monospace,Consolas,monospace;color:var(--dim);border:1px solid var(--line);border-radius:6px;padding:1px 6px;background:color-mix(in srgb,var(--panel) 55%,transparent)}
|
|
160
172
|
.fi-head time{margin-left:auto;color:var(--dim);font:10px ui-monospace,Consolas,monospace;flex:none}
|
|
161
|
-
.fi-msg{color:var(--tx)}
|
|
162
|
-
.fi-body{margin-top:
|
|
163
|
-
.fi-body.clamp{max-height:
|
|
164
|
-
.fi-more{margin-top:
|
|
173
|
+
.fi-msg{color:var(--tx);font-size:12px}
|
|
174
|
+
.fi-body{margin-top:6px;font-size:11.5px;line-height:1.6;color:color-mix(in srgb,var(--tx) 78%,var(--dim));white-space:pre-wrap;word-break:break-word}
|
|
175
|
+
.fi-body.clamp{max-height:106px;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 66%,transparent);mask-image:linear-gradient(180deg,#000 66%,transparent)}
|
|
176
|
+
.fi-more{margin-top:6px;font-size:11px;font-weight:600;color:var(--acc);background:color-mix(in srgb,var(--acc) 10%,transparent);border:1px solid color-mix(in srgb,var(--acc) 28%,var(--line));border-radius:7px;padding:3px 10px}.fi-more:hover{background:color-mix(in srgb,var(--acc) 17%,transparent)}
|
|
165
177
|
.fi-delegation{--evc:var(--purple)}.fi-result{--evc:var(--ok)}.fi-failure,.fi-blocked{--evc:var(--err)}
|
|
166
|
-
.fi-failure,.fi-blocked{background:color-mix(in srgb,var(--err) 7%,transparent)}
|
|
167
178
|
.fi-log{--evc:var(--dim)}.fi-log.task{--evc:var(--acc)}.fi-log.ok{--evc:var(--ok)}.fi-log.error{--evc:var(--err)}.fi-log.warn{--evc:var(--warn)}.fi-log.stage{--evc:var(--purple)}.fi-log.info{--evc:var(--acc)}
|
|
168
179
|
.fi-log.error .fi-msg,.fi-log.warn .fi-msg{color:var(--evc)}.fi-log.ok .fi-msg,.fi-log.task .fi-msg{font-weight:600}
|
|
169
180
|
/* Teslimat */
|
|
@@ -332,10 +343,16 @@ details summary{cursor:pointer;color:var(--dim);font-size:12px} pre{white-space:
|
|
|
332
343
|
<section class="stack">
|
|
333
344
|
<div class="card mission-card" id="missionCard">
|
|
334
345
|
<div class="mission-top"><div><div class="mission-title" id="missionTitle">Takım görevi bekleniyor</div><div class="mission-sub" id="missionSub">Operatör bir hedef aldığında ekibini burada kuracak.</div></div><div class="grow"></div><span class="mission-status" id="missionStatus" hidden><span class="sdot"></span><span id="missionStatusText">Hazır</span></span><span class="badge" id="missionStats">0 mesaj · 0 çağrı</span></div>
|
|
335
|
-
<div id="teamMap" class="team-map"><div class="empty" style="width:100%">Henüz aktif ekip yok.</div></div>
|
|
336
346
|
<div class="mission-banner" id="missionBanner"><div class="mb-ico" id="mbIco">✓</div><div style="min-width:0"><div class="mb-title" id="mbTitle"></div><div class="mb-answer" id="mbAnswer" hidden></div><div class="mb-sub" id="mbSub"></div></div></div>
|
|
347
|
+
<div class="flow-seg">
|
|
348
|
+
<div class="flow-seg-head"><span class="lbl">Ekip</span><span class="ln"></span><span class="hint">operatör + uzman ajanlar</span></div>
|
|
349
|
+
<div id="teamMap" class="team-map"><div class="empty" style="width:100%">Henüz aktif ekip yok.</div></div>
|
|
350
|
+
</div>
|
|
351
|
+
<div class="flow-seg">
|
|
352
|
+
<div class="flow-seg-head"><span class="lbl">Canlı akış</span><span class="ln"></span><span class="hint">canlı görev günlüğü</span></div>
|
|
353
|
+
<div id="feed" class="feed"><div class="empty">Henüz etkinlik yok.</div></div>
|
|
354
|
+
</div>
|
|
337
355
|
</div>
|
|
338
|
-
<div class="card"><div class="command-head"><h2>Takım akışı</h2><div class="grow"></div><span class="muted">Canlı görev günlüğü</span></div><div id="feed" class="feed"><div class="empty">Henüz etkinlik yok.</div></div></div>
|
|
339
356
|
<details class="card live-details"><summary>Teknik ayrıntılar <span class="muted">Canlı agent terminalleri</span></summary><div class="live-body"><div class="command-head"><span class="muted">Operatör ve uzmanların ham çıktıları</span><div class="grow"></div><button class="sm" onclick="clearLive()">Temizle</button></div><div id="agentGrid" class="agent-grid"><div class="empty">Bir görev başladığında terminal çıktıları burada görünür.</div></div></div></details>
|
|
340
357
|
</section>
|
|
341
358
|
</main>
|
|
@@ -458,7 +475,7 @@ function cliColor(id){return CLI_COLOR[id]||CLI_COLOR.custom}
|
|
|
458
475
|
// aktivite olaylarinda dogrudan CLI id'siyle gelir; uzman ise config.agents anahtaridir.
|
|
459
476
|
function agentCli(name){if(!name)return 'custom';const key=String(name).toLowerCase();if(CLI_COLOR[key]&&key!=='custom')return key;const a=STATE.config.agents&&STATE.config.agents[name];return a?adapterOf(a):'custom'}
|
|
460
477
|
function agentColor(name){return cliColor(agentCli(name))}
|
|
461
|
-
const CLI_SETTINGS_DEFAULTS={codex:{model:'',reasoningEffort:'medium',serviceTier:'fast'},opencode:{model:''}};
|
|
478
|
+
const CLI_SETTINGS_DEFAULTS={codex:{model:'',reasoningEffort:'medium',serviceTier:'fast'},claude:{model:''},opencode:{model:''}};
|
|
462
479
|
function cloneCliSettings(value){const source=value&&typeof value==='object'?value:{};return Object.fromEntries(Object.entries(CLI_SETTINGS_DEFAULTS).map(([id,defaults])=>[id,{...defaults,...(source[id]||{})}]))}
|
|
463
480
|
function adapterOf(a){const b=String(a?.adapter||a?.cmd||'').toLowerCase();if(b.includes('codex'))return 'codex';if(b.includes('claude'))return 'claude';if(b.includes('gemini'))return 'gemini';if(b.includes('opencode'))return 'opencode';return b||'custom'}
|
|
464
481
|
function commandAdapter(command){const b=String(command||'').replace(/\\/g,'/').split('/').pop().toLowerCase().replace(/\.(cmd|bat|exe|ps1)$/,'');if(b.includes('codex'))return 'codex';if(b.includes('claude'))return 'claude';if(b.includes('gemini'))return 'gemini';if(b.includes('opencode'))return 'opencode';return 'custom'}
|
|
@@ -681,15 +698,20 @@ window.addEventListener('pagehide',()=>{try{es?.close()}catch{}});
|
|
|
681
698
|
window.addEventListener('pageshow',e=>{if(e.persisted)location.reload()});
|
|
682
699
|
|
|
683
700
|
/* ---- Ayarlar ---- */
|
|
684
|
-
function normalizeDraftAgentModels(){for(const agent of draftAgents){const adapter=adapterOf(agent);if(adapter==='
|
|
701
|
+
function normalizeDraftAgentModels(){for(const agent of draftAgents){const adapter=adapterOf(agent);if(adapter==='gemini'){delete agent.model;delete agent.modelOverride}else if(adapter==='opencode'&&agent.autoDiscovered&&agent.model&&agent.modelOverride!==true)delete agent.model}}
|
|
685
702
|
function setAgentModel(index,value){const agent=draftAgents[index];if(!agent)return;const model=String(value||'').trim();if(model)agent.model=model;else delete agent.model;if(agent.autoDiscovered){if(model)agent.modelOverride=true;else delete agent.modelOverride}}
|
|
686
|
-
function openSettings(){draftAgents=Object.entries(STATE.config.agents||{}).map(([name,a])=>({name,...JSON.parse(JSON.stringify(a))}));draftCliSettings=cloneCliSettings(STATE.config.cliSettings);normalizeDraftAgentAdapters();normalizeDraftAgentModels();draftIgnoredAdapters=[...(STATE.config.discoveryIgnoredAdapters||[])];$('#settings').classList.add('open');showTab('agents');ensureCodexModelCatalog().then(()=>{if(tab==='agents')refreshAgentCodexModels()
|
|
703
|
+
function openSettings(){draftAgents=Object.entries(STATE.config.agents||{}).map(([name,a])=>({name,...JSON.parse(JSON.stringify(a))}));draftCliSettings=cloneCliSettings(STATE.config.cliSettings);normalizeDraftAgentAdapters();normalizeDraftAgentModels();draftIgnoredAdapters=[...(STATE.config.discoveryIgnoredAdapters||[])];$('#settings').classList.add('open');showTab('agents');Promise.allSettled([ensureCodexModelCatalog(),ensureClaudeModelCatalog()]).then(()=>{if(tab==='agents'){refreshAgentCodexModels();refreshAgentClaudeModels()}})}
|
|
687
704
|
function closeSettings(){$('#settings').classList.remove('open')}
|
|
688
705
|
function showTab(name){tab=name;document.querySelectorAll('.tabs button').forEach(b=>b.classList.toggle('active',b.dataset.tab===name));const c=$('#settingsContent');if(name==='agents')renderAgents(c);else if(name==='clis')renderClis(c);else if(name==='operator')renderOperator(c);else if(name==='skills')renderSkills(c);else renderGeneral(c)}
|
|
689
706
|
function openCodeGroups(models){const groups=new Map();for(const model of [...new Set(models||[])]){const provider=String(model).split('/')[0];if(!groups.has(provider))groups.set(provider,[]);groups.get(provider).push(model)}const preferred=['opencode','opencode-go','minimax-coding-plan'];const providers=[...groups.keys()].sort((a,b)=>{const rank=x=>x==='ollama'?999:(preferred.includes(x)?preferred.indexOf(x):100);return rank(a)-rank(b)||a.localeCompare(b)});return providers.map(provider=>({provider,models:groups.get(provider).sort()}))}
|
|
690
707
|
function openCodeModelOptions(selected,scope='global'){const status=(STATE.cliStatus||[]).find(x=>x.id==='opencode'),models=[...(status?.models||[])];if(selected&&!models.includes(selected))models.push(selected);const inherited=draftCliSettings.opencode?.model?`CLI ayarını kullan (${draftCliSettings.opencode.model})`:`CLI ayarını kullan (otomatik${status?.recommendedModel?`: ${status.recommendedModel}`:''})`,first=scope==='agent'?inherited:`Otomatik önerilen${status?.recommendedModel?` (${status.recommendedModel})`:''}`;return `<option value="">${esc(first)}</option>`+openCodeGroups(models).map(group=>`<optgroup label="${esc(group.provider)}">${group.models.map(model=>`<option value="${esc(model)}" ${model===selected?'selected':''}>${esc(model)}</option>`).join('')}</optgroup>`).join('')}
|
|
691
|
-
|
|
708
|
+
let claudeModelCatalog=[],claudeModelsLoaded=false,claudeModelsPromise=null;
|
|
709
|
+
async function ensureClaudeModelCatalog(){if(claudeModelsLoaded)return claudeModelCatalog;if(!claudeModelsPromise)claudeModelsPromise=api('/api/claude/models').then(response=>{claudeModelCatalog=response.models||[];claudeModelsLoaded=true;return claudeModelCatalog}).finally(()=>{claudeModelsPromise=null});return claudeModelsPromise}
|
|
710
|
+
function claudeModelLabel(model){const name=model.displayName||model.id,detail=model.description||model.resolvedModel||'',id=model.id||'';return [name,detail,id&&id!==name?`kimlik: ${id}`:''].filter(Boolean).join(' · ')}
|
|
711
|
+
function claudeModelOptions(selected,scope='global'){const defaultModel=claudeModelCatalog.find(model=>model.id==='default'),models=claudeModelCatalog.filter(model=>model.id!=='default');if(selected&&!models.some(model=>model.id===selected))models.push({id:selected,displayName:selected+' (kayıtlı)'});const inheritedId=draftCliSettings.claude?.model||'',inheritedModel=claudeModelCatalog.find(model=>model.id===inheritedId),inherited=inheritedId?(inheritedModel?claudeModelLabel(inheritedModel):inheritedId):(defaultModel?claudeModelLabel(defaultModel):'Claude Code varsayılanı'),first=scope==='agent'?`CLI ayarını kullan (${inherited})`:`Otomatik — ${defaultModel?claudeModelLabel(defaultModel):'hesap/sağlayıcı/kurum varsayılanı'}`;return `<option value="">${esc(first)}</option>`+models.map(model=>`<option value="${esc(model.id)}" ${model.id===selected?'selected':''}>${esc(claudeModelLabel(model))}</option>`).join('')}
|
|
712
|
+
function agentModelControl(a,i){const adapter=adapterOf(a),selected=String(a.model||'');if(adapter==='opencode')return `<label>OpenCode modeli</label><select onchange="setAgentModel(${i},this.value)">${openCodeModelOptions(selected,'agent')}</select>`;if(adapter==='claude')return `<label>Claude Code modeli</label><select class="agentClaudeModel" data-agent-index="${i}" onchange="setAgentModel(${i},this.value)">${claudeModelOptions(selected,'agent')}</select>`;if(adapter==='codex'){const models=[...codexModelCatalog],inherited=draftCliSettings.codex?.model||'Codex varsayılanı';if(selected&&!models.some(x=>x.id===selected))models.push({id:selected,displayName:selected+' (kayıtlı)'});return `<label>Model</label><select class="agentCodexModel" data-agent-index="${i}" onchange="setAgentModel(${i},this.value)"><option value="">CLI ayarını kullan (${esc(inherited)})</option>${models.map(m=>`<option value="${esc(m.id)}" ${m.id===selected?'selected':''}>${esc(m.displayName||m.id)}</option>`).join('')}</select>`}return ''}
|
|
692
713
|
function refreshAgentCodexModels(){document.querySelectorAll('.agentCodexModel').forEach(select=>{const index=+select.dataset.agentIndex,selected=String(draftAgents[index]?.model||''),inherited=draftCliSettings.codex?.model||'Codex varsayılanı',models=[...codexModelCatalog];if(selected&&!models.some(x=>x.id===selected))models.push({id:selected,displayName:selected+' (kayıtlı)'});select.innerHTML=`<option value="">CLI ayarını kullan (${esc(inherited)})</option>`+models.map(m=>`<option value="${esc(m.id)}">${esc(m.displayName||m.id)}</option>`).join('');select.value=selected})}
|
|
714
|
+
function refreshAgentClaudeModels(){document.querySelectorAll('.agentClaudeModel').forEach(select=>{const index=+select.dataset.agentIndex,selected=String(draftAgents[index]?.model||'');select.innerHTML=claudeModelOptions(selected,'agent');select.value=selected})}
|
|
693
715
|
function renderAgents(c){const found=(STATE.cliStatus||[]).map(x=>`<span class="badge" style="color:${x.installed&&(x.id!=='opencode'||x.ready!==false)?'var(--ok)':x.installed?'var(--warn)':'var(--dim)'}">${x.installed?'●':'○'} ${esc(x.id)} ${esc(x.id==='opencode'&&x.installed?(x.ready===false?'model seçilmeli':`${x.version||'kurulu'} · model hazır`):(x.version||'kurulu değil'))}</span>`).join(' '),open=(STATE.cliStatus||[]).find(x=>x.id==='opencode'),platform=STATE.platform==='win32'?'windows':STATE.platform==='darwin'?'macos':'linux',install=open?.install?.[platform];
|
|
694
716
|
c.innerHTML=`<div class="item"><div class="row" style="flex-wrap:wrap"><b>Kurulu CLI taraması</b>${found}<div class="grow"></div>${draftIgnoredAdapters.length?`<button class="sm" onclick="restoreDiscovered()">Gizlenenleri geri getir (${draftIgnoredAdapters.length})</button>`:''}<button class="sm" onclick="scanClis()">Yeniden Tara</button></div><p class="muted">Kurulu CLI'lar otomatik tanınır. Otomatik oluşturulmuş bir agent'ı silerseniz tercihiniz korunur ve sonraki taramada geri eklenmez.</p>${open&&!open.installed?`<div style="border:1px solid var(--warn);border-radius:8px;padding:8px"><b style="color:var(--warn)">OpenCode kurulu değil</b><div class="muted">Bu cihaz için kurulum:</div><code>${esc(install||'npm install -g opencode-ai')}</code><div class="muted" style="margin-top:4px">Sağlayıcı bağlantısı: <code>${esc(open.install?.auth||'opencode auth login')}</code></div></div>`:''}</div>`
|
|
695
717
|
+`<div class="hint">Buradaki agent'lar <b>operatörün altında çalışan uzmanlardır</b>. Operatör bunlardan biri değildir — ayrı "Operatör" sekmesinde bir CLI olarak seçilir. Bir uzmanı silmek operatörü etkilemez. Agent'ın <b>rolü görev türünü bağlayıcı biçimde sınırlar</b>: executor uygulama, reviewer inceleme, planner planlama yapar. Dengeli uygulama görevlerinde hazır üç rol <b>planner → executor → reviewer</b> sırasıyla aynı turda çalıştırılır.</div>`
|
|
@@ -699,7 +721,7 @@ function renderAgents(c){const found=(STATE.cliStatus||[]).map(x=>`<span class="
|
|
|
699
721
|
if(currentRole&&workerRoles().includes(currentRole))loadRole()}
|
|
700
722
|
function removeDraftAgent(index){const agent=draftAgents[index];if(agent?.autoDiscovered){const adapter=adapterOf(agent);if(CLI_LABEL[adapter]&&!draftIgnoredAdapters.includes(adapter))draftIgnoredAdapters.push(adapter)}draftAgents.splice(index,1);renderAgents($('#settingsContent'))}
|
|
701
723
|
function addAgentFromCli(){const adapter=$('#newAgentCli')?.value||'custom',template=(STATE.cliStatus||[]).find(x=>x.id===adapter),requested=$('#newAgentName')?.value.trim();let base=requested||(adapter==='custom'?'yeni-agent':`${adapter}-agent`),name=base,n=2;while(draftAgents.some(a=>a.name===name))name=`${base}-${n++}`;draftAgents.push({name,adapter,cmd:template?.command||(adapter==='custom'?'':adapter),args:[...(template?.defaultArgs||[])],enabled:true,autoDiscovered:false,description:template?.description||'',capabilities:[...(template?.capabilities||['implementation'])],roleFile:template?.roleFile||'roles/executor.md',costTier:'standard',timeoutSeconds:template?.timeoutSeconds||STATE.config.agentTimeoutSeconds||900,silenceTimeoutSeconds:template?.silenceTimeoutSeconds||STATE.config.cliSilenceTimeoutSeconds||300});renderAgents($('#settingsContent'));notify(`${cliLabel(adapter)} varsayılanlarıyla ${name} oluşturuldu.`)}
|
|
702
|
-
async function scanClis(){try{const localDrafts=draftAgents.map(a=>JSON.parse(JSON.stringify(a))),localCliSettings=cloneCliSettings(draftCliSettings);const r=await api('/api/cli/discover','POST',{ignoredAdapters:draftIgnoredAdapters});STATE.cliStatus=r.cliStatus;STATE.config={...r.config,cliSettings:localCliSettings,discoveryIgnoredAdapters:[...draftIgnoredAdapters]};draftCliSettings=localCliSettings;const serverAgents=Object.entries(r.config.agents||{}).map(([name,a])=>({name,...JSON.parse(JSON.stringify(a))}));for(const agent of serverAgents){if(!localDrafts.some(a=>a.name===agent.name||adapterOf(a)===adapterOf(agent)))localDrafts.push(agent)}draftAgents=localDrafts;showTab(tab);refreshOperatorSelect();notify(r.changed?'CLI taraması güncellendi; yerel taslaklar korundu.':'Tarama tamamlandı; yerel taslaklar korundu.')}catch(e){notify(e.message,true)}}
|
|
724
|
+
async function scanClis(){try{const localDrafts=draftAgents.map(a=>JSON.parse(JSON.stringify(a))),localCliSettings=cloneCliSettings(draftCliSettings);const r=await api('/api/cli/discover','POST',{ignoredAdapters:draftIgnoredAdapters});STATE.cliStatus=r.cliStatus;STATE.config={...r.config,cliSettings:localCliSettings,discoveryIgnoredAdapters:[...draftIgnoredAdapters]};draftCliSettings=localCliSettings;claudeModelCatalog=[];claudeModelsLoaded=false;const serverAgents=Object.entries(r.config.agents||{}).map(([name,a])=>({name,...JSON.parse(JSON.stringify(a))}));for(const agent of serverAgents){if(!localDrafts.some(a=>a.name===agent.name||adapterOf(a)===adapterOf(agent)))localDrafts.push(agent)}draftAgents=localDrafts;showTab(tab);refreshOperatorSelect();notify(r.changed?'CLI taraması güncellendi; yerel taslaklar korundu.':'Tarama tamamlandı; yerel taslaklar korundu.')}catch(e){notify(e.message,true)}}
|
|
703
725
|
async function restoreDiscovered(){draftIgnoredAdapters=[];await scanClis()}
|
|
704
726
|
async function selectRole(name){currentRole=name;await loadRole()}
|
|
705
727
|
async function loadRole(){const r=await api(`/api/roles/${encodeURIComponent(currentRole)}`);const ed=$('#roleEditor');if(!ed)return;ed.innerHTML=`<label>roles/${esc(currentRole)}</label><textarea id="roleText">${esc(r.content)}</textarea><button class="primary sm" onclick="saveRole()">Rolü Kaydet</button> <button class="danger sm" onclick="deleteRoleFile()">Sil</button>`}
|
|
@@ -710,8 +732,9 @@ async function deleteRoleFile(){if(!await appConfirm({title:'Rol silinsin mi?',b
|
|
|
710
732
|
let codexModelCatalog=[],codexModelsPromise=null;
|
|
711
733
|
async function ensureCodexModelCatalog(){if(codexModelCatalog.length)return codexModelCatalog;if(!codexModelsPromise)codexModelsPromise=api('/api/codex/models').then(response=>{codexModelCatalog=response.models||[];return codexModelCatalog}).finally(()=>{codexModelsPromise=null});return codexModelsPromise}
|
|
712
734
|
async function loadCodexModels(selected){const select=$('#codexModel');if(!select)return;try{await ensureCodexModelCatalog();if($('#codexModel')!==select)return;select.innerHTML='<option value="">Codex varsayılanı</option>'+codexModelCatalog.map(m=>`<option value="${esc(m.id)}">${esc(m.displayName||m.id)}</option>`).join('');if(selected&&!codexModelCatalog.some(m=>m.id===selected))select.insertAdjacentHTML('beforeend',`<option value="${esc(selected)}">${esc(selected)} (kayıtlı)</option>`);select.value=selected||'';const hint=$('#codexModelHint');if(hint)hint.textContent=`Codex hesabından ${codexModelCatalog.length} aktif model alındı; boş seçim CLI varsayılanını kullanır.`;updateCodexCapabilities()}catch(error){if($('#codexModel')!==select)return;select.innerHTML='<option value="">Codex varsayılanı</option>';if(selected){select.insertAdjacentHTML('beforeend',`<option value="${esc(selected)}">${esc(selected)} (kayıtlı)</option>`);select.value=selected}const hint=$('#codexModelHint');if(hint)hint.textContent='Aktif model listesi alınamadı: '+error.message}}
|
|
735
|
+
async function loadClaudeModels(selected){const select=$('#claudeModel');if(!select)return;try{await ensureClaudeModelCatalog();if($('#claudeModel')!==select)return;select.innerHTML=claudeModelOptions(selected,'global');select.value=selected||'';const hint=$('#claudeModelHint');if(hint)hint.textContent=`Bu Claude Code hesabı, sağlayıcısı ve kurum politikası için ${claudeModelCatalog.filter(model=>model.id!=='default').length} seçilebilir model bildirildi. Liste bir model isteği çalıştırılmadan Claude Code'dan alınır.`;refreshAgentClaudeModels()}catch(error){if($('#claudeModel')!==select)return;claudeModelCatalog=[];select.innerHTML=claudeModelOptions(selected,'global');select.value=selected||'';const hint=$('#claudeModelHint');if(hint)hint.textContent='Claude Code model kataloğu alınamadı; yalnızca varsayılan veya önceden kayıtlı seçim kullanılabilir: '+error.message}}
|
|
713
736
|
function updateCodexCapabilities(){const settings=draftCliSettings.codex||(draftCliSettings.codex={...CLI_SETTINGS_DEFAULTS.codex}),chosen=$('#codexModel')?.value||'',model=codexModelCatalog.find(x=>x.id===chosen)||(chosen?'':codexModelCatalog.find(x=>x.isDefault)),effort=$('#codexEffort'),tier=$('#codexServiceTier');settings.model=chosen;if(effort){const values=(model?.reasoningEfforts||[]).map(x=>x.id);if(!values.length)values.push('low','medium','high','xhigh','max','ultra');const current=settings.reasoningEffort||'medium';effort.innerHTML=values.map(x=>`<option value="${esc(x)}">${esc(x)}</option>`).join('');effort.value=values.includes(current)?current:(model?.defaultReasoningEffort||values[0]);settings.reasoningEffort=effort.value}if(tier){const values=(model?.serviceTiers||[]).map(x=>({id:x.id,label:x.name||x.id}));if(!values.length)values.push({id:'fast',label:'fast'},{id:'priority',label:'priority'});const current=settings.serviceTier||'fast';tier.innerHTML=values.map(x=>`<option value="${esc(x.id)}">${esc(x.label)}${x.label!==x.id?' ('+esc(x.id)+')':''}</option>`).join('');tier.value=values.some(x=>x.id===current)?current:(model?.defaultServiceTier||values[0].id);settings.serviceTier=tier.value}}
|
|
714
|
-
function renderClis(c){const statuses=STATE.cliStatus||[],available=statuses.filter(x=>x.installed&&CLI_LABEL[x.id]);const ids=available.length?available.map(x=>x.id):Object.keys(CLI_LABEL),cards=[];for(const id of ids){const status=statuses.find(x=>x.id===id),defaults=CLI_SETTINGS_DEFAULTS[id],settings=defaults?(draftCliSettings[id]||(draftCliSettings[id]={...defaults})):null;if(id==='codex')cards.push(`<div class="item"><div class="row"><b>Codex</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><div class="grid2"><div><label>Model</label><select id="codexModel" onchange="draftCliSettings.codex.model=this.value;updateCodexCapabilities()"><option value="">Modeller yükleniyor…</option></select><div id="codexModelHint" class="muted">Codex hesabındaki aktif modeller getiriliyor.</div></div><div><label>Reasoning effort</label><select id="codexEffort" onchange="draftCliSettings.codex.reasoningEffort=this.value"><option>${esc(settings.reasoningEffort)}</option></select></div><div><label>Servis hızı</label><select id="codexServiceTier" onchange="draftCliSettings.codex.serviceTier=this.value"><option>${esc(settings.serviceTier)}</option></select></div></div></div>`);else if(id==='opencode')cards.push(`<div class="item"><div class="row"><b>OpenCode</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><label>Model</label><select id="opencodeModel" onchange="draftCliSettings.opencode.model=this.value">${openCodeModelOptions(settings.model,'global')}</select><div class="muted">Tüm sağlayıcılar listelenir; boş seçim uygun modeli otomatik seçer.</div></div>`);else cards.push(`<div class="item"><div class="row"><b>${esc(cliLabel(id))}</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><div class="muted">Bu CLI için doğrulanmış model kataloğu yok; model seçimi sunulmaz ve CLI varsayılanı kullanılır.</div></div>`) }c.innerHTML=`<div class="hint">Model seçimi yalnızca doğrulanmış katalog sağlayan CLI'larda gösterilir. Seçilen model o CLI'nın <b>tüm kullanımlarına</b> uygulanır; agent ekranındaki boş override alanı miras alınan modeli adıyla gösterir.</div>${cards.join('')}`;if(ids.includes('codex'))loadCodexModels(draftCliSettings.codex.model||'')}
|
|
737
|
+
function renderClis(c){const statuses=STATE.cliStatus||[],available=statuses.filter(x=>x.installed&&CLI_LABEL[x.id]);const ids=available.length?available.map(x=>x.id):Object.keys(CLI_LABEL),cards=[];for(const id of ids){const status=statuses.find(x=>x.id===id),defaults=CLI_SETTINGS_DEFAULTS[id],settings=defaults?(draftCliSettings[id]||(draftCliSettings[id]={...defaults})):null;if(id==='codex')cards.push(`<div class="item"><div class="row"><b>Codex</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><div class="grid2"><div><label>Model</label><select id="codexModel" onchange="draftCliSettings.codex.model=this.value;updateCodexCapabilities()"><option value="">Modeller yükleniyor…</option></select><div id="codexModelHint" class="muted">Codex hesabındaki aktif modeller getiriliyor.</div></div><div><label>Reasoning effort</label><select id="codexEffort" onchange="draftCliSettings.codex.reasoningEffort=this.value"><option>${esc(settings.reasoningEffort)}</option></select></div><div><label>Servis hızı</label><select id="codexServiceTier" onchange="draftCliSettings.codex.serviceTier=this.value"><option>${esc(settings.serviceTier)}</option></select></div></div></div>`);else if(id==='claude')cards.push(`<div class="item"><div class="row"><b>Claude Code</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><label>Model</label><select id="claudeModel" onchange="draftCliSettings.claude.model=this.value"><option value="">Modeller yükleniyor…</option></select><div id="claudeModelHint" class="muted">Bu kullanıcının Claude Code hesabı, sağlayıcısı ve kurum politikası için kullanılabilir modeller getiriliyor.</div></div>`);else if(id==='opencode')cards.push(`<div class="item"><div class="row"><b>OpenCode</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><label>Model</label><select id="opencodeModel" onchange="draftCliSettings.opencode.model=this.value">${openCodeModelOptions(settings.model,'global')}</select><div class="muted">Tüm sağlayıcılar listelenir; boş seçim uygun modeli otomatik seçer.</div></div>`);else cards.push(`<div class="item"><div class="row"><b>${esc(cliLabel(id))}</b><div class="grow"></div><span class="badge">${esc(status?.version||'CLI')}</span></div><div class="muted">Bu CLI için doğrulanmış model kataloğu yok; model seçimi sunulmaz ve CLI varsayılanı kullanılır.</div></div>`) }c.innerHTML=`<div class="hint">Model seçimi yalnızca doğrulanmış katalog sağlayan CLI'larda gösterilir. Seçilen model o CLI'nın <b>tüm kullanımlarına</b> uygulanır; agent ekranındaki boş override alanı miras alınan modeli adıyla gösterir.</div>${cards.join('')}`;if(ids.includes('codex'))loadCodexModels(draftCliSettings.codex.model||'');if(ids.includes('claude'))loadClaudeModels(draftCliSettings.claude.model||'')}
|
|
715
738
|
function renderOperator(c){const o=STATE.config.operator||{},opts=operatorCliOptions(true),curCli=opts.some(x=>x.cli===o.cli)?o.cli:opts[0]?.cli;c.innerHTML=`<div class="hint">Operatör, uzman agent'lardan <b>bağımsız bir CLI'dır</b>. Burada yalnızca ekip yönetimi ve tur sınırları ayarlanır. CLI modellerini “CLI'lar ve Modeller” sekmesinden seçebilirsiniz.</div><div class="item"><div class="grid2"><div><label>Operatör CLI'sı — operator.md'yi çalıştıracak CLI</label><select id="defaultOperator">${opts.map(x=>`<option value="${x.cli}" ${x.cli===curCli?'selected':''}>${esc(x.label)}</option>`).join('')||'<option value="">Kurulu CLI yok</option>'}</select></div><div><label>Maksimum takım turu</label><input id="maxRounds" type="number" value="${o.maxRounds||6}"></div><div><label>Tur başına maksimum delegasyon</label><input id="maxDelegations" type="number" value="${o.maxDelegationsPerRound||8}"></div><div><label>JSON protokol tekrarları</label><input id="protocolRetries" type="number" value="${o.protocolRetries??1}"></div></div></div><div class="item"><label>Operatör rolü — roles/operator.md (akışı buradan kurgularsınız)</label><div id="operatorRoleBox" class="muted">yükleniyor…</div></div>`;loadOperatorRole()}
|
|
716
739
|
async function loadOperatorRole(){try{const r=await api('/api/roles/operator.md');const box=$('#operatorRoleBox');if(box)box.innerHTML=`<textarea id="operatorRoleText">${esc(r.content)}</textarea><button class="primary sm" style="margin-top:6px" onclick="saveOperatorRole()">Operatör rolünü kaydet</button>`}catch(e){const box=$('#operatorRoleBox');if(box)box.textContent=e.message}}
|
|
717
740
|
async function saveOperatorRole(){await api('/api/roles/operator.md','PUT',{content:$('#operatorRoleText').value});notify('Operatör rolü kaydedildi')}
|