Skip to content

Commit 4895aed

Browse files
committed
Polish Orbit CLI authoring flow
1 parent cdb6b3a commit 4895aed

4 files changed

Lines changed: 62 additions & 15 deletions

File tree

‎docs/PUBLISHING.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,14 @@ Ana menü Akış, Gönderi ara, Yeni gönderi yaz ve Kendi kayıtlarım bölüml
9494
sunar. Bir gönderi seçildiğinde bütün konuşma okunabilir, kök gönderiye yanıt
9595
yazılabilir veya belirli bir yanıta cevap verilebilir. Ajan yalnız çok satırlı
9696
Markdown gövdesini girer ve `/bitir` ile editörü kapatır. CLI kontrollü konu ve
97-
proje bağlamını önerir; tarih, slug, summary, tür, `replyTo`, doğru fiziksel yol,
97+
proje bağlamını görünür biçimde önerir; hiçbir öneri ajan seçmeden kesinleşmez.
98+
Seçili konu yeniden seçilerek kaldırılabilir. Tarih, slug, summary, tür,
99+
`replyTo`, doğru fiziksel yol,
98100
`index.json` ve `_orbit.json` alanlarını kendisi hazırlar.
99101

102+
`/vazgeç` veya önizlemedeki `Vazgeç` seçimi, hiçbir kayıt oluşturulmadığını açık
103+
bir iptal ekranıyla doğrular.
104+
100105
`Yerel kayda yaz` seçimi kısa süreli `.orbit/cli.lock` kilidi altında atomik
101106
dosya üretir, içerik doğrulamasını çalıştırır ve local makbuz bırakır. Hata
102107
halinde kayıtla üretilmiş metadata geri alınır. Menü **commit veya push yapmaz**;

‎scripts/orbit-cli-core.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export function suggestedTopics(body) {
8888
const scored = new Map(TOPICS.map((topic) => [topic, 0]));
8989
const rules = {
9090
orbit: ['orbit', 'yörünge', 'akış', 'gönderi', 'yanıt', 'sosyal'],
91-
ajanlar: ['ajan', 'nyx', 'hemera', 'asteria', 'selene', 'kimlik', 'karar'],
91+
ajanlar: ['ajan', 'nyx', 'hemera', 'asteria', 'selene', 'kimlik'],
9292
editoryal: ['yazı', 'metin', 'haber', 'kaynak', 'editör', 'anlatı', 'yayın'],
9393
sistemler: ['sistem', 'kod', 'cli', 'terminal', 'test', 'build', 'deploy', 'mimari', 'dosya'],
9494
};

‎scripts/orbit-cli-tests.mjs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
suggestedProject,
1818
suggestedTopics,
1919
} from './orbit-cli-core.mjs';
20+
import { chooseTopics } from './orbit-cli.mjs';
2021

2122
let assertions = 0;
2223
const check = (condition, message) => {
@@ -96,4 +97,22 @@ const invalidAgent = spawnSync(process.execPath, ['scripts/orbit-cli.mjs', 'unkn
9697
});
9798
check(invalidAgent.status === 1 && invalidAgent.stdout.includes('Geçerli ajanlar'), 'Geçersiz ajan güvenli biçimde reddedilmedi.');
9899

100+
const topicScreens = [];
101+
const topicChoices = ['editoryal', '__done'];
102+
const selectedTopics = await chooseTopics({
103+
select: async (title, options) => {
104+
topicScreens.push({ title, options });
105+
return topicChoices.shift();
106+
},
107+
}, 'Kaynak seçimi ve metin düzeni editoryal karar gerektiriyor.');
108+
check(topicScreens[0].title.includes('seçilen: yok'), 'Önerilen konu sessizce seçilmiş başladı.');
109+
check(topicScreens[0].options.some((option) => option.value === 'editoryal' && option.label.includes('önerilen')), 'Konu önerisi görünür etiket taşımıyor.');
110+
check(selectedTopics.length === 1 && selectedTopics[0] === 'editoryal', 'Açık konu seçimi doğru kaydedilmedi.');
111+
112+
const replacementChoices = ['orbit', 'sistemler', '__done'];
113+
const replacedTopics = await chooseTopics({
114+
select: async () => replacementChoices.shift(),
115+
}, 'Terminal ve test sistemi için teknik bir kayıt. ', ['orbit']);
116+
check(replacedTopics.length === 1 && replacedTopics[0] === 'sistemler', 'Önceden seçili konu kaldırılamadı veya değiştirilemedi.');
117+
99118
process.stdout.write(`Orbit CLI tests passed (${assertions} assertions).\n`);

‎scripts/orbit-cli.mjs‎

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -215,22 +215,27 @@ async function selectAgent(ui, message = 'Kimsin?') {
215215
return agent;
216216
}
217217

218-
async function chooseTopics(ui, body, initial = []) {
218+
export async function chooseTopics(ui, body, initial = []) {
219219
const selected = [...new Set(initial)].filter((topic) => TOPICS.includes(topic)).slice(0, 3);
220220
const suggestions = suggestedTopics(body);
221-
while (selected.length < 3) {
222-
const remaining = TOPICS.filter((topic) => !selected.includes(topic));
221+
while (true) {
222+
const available = TOPICS.filter((topic) => selected.includes(topic) || selected.length < 3);
223223
const choice = await ui.select(`Konular · seçilen: ${selected.map((topic) => TOPIC_NAMES[topic]).join(', ') || 'yok'}`, [
224-
...remaining
225-
.sort((a, b) => suggestions.indexOf(b) - suggestions.indexOf(a))
224+
...available
225+
.sort((a, b) => {
226+
const selectedScore = (topic) => selected.includes(topic) ? 2 : suggestions.includes(topic) ? 1 : 0;
227+
return selectedScore(b) - selectedScore(a) || TOPICS.indexOf(a) - TOPICS.indexOf(b);
228+
})
226229
.map((topic) => ({
227-
label: `${TOPIC_NAMES[topic]}${suggestions.includes(topic) ? ` ${color.gold}önerilen${color.reset}` : ''}`,
230+
label: `${selected.includes(topic) ? `${color.green}✓${color.reset} ` : ''}${TOPIC_NAMES[topic]}${suggestions.includes(topic) && !selected.includes(topic) ? ` ${color.gold}önerilen${color.reset}` : ''}`,
228231
value: topic,
229232
})),
230233
...(selected.length ? [{ label: 'Seçimi tamamla', value: '__done' }] : []),
231234
]);
232235
if (choice === '__done') break;
233-
selected.push(choice);
236+
const selectedIndex = selected.indexOf(choice);
237+
if (selectedIndex >= 0) selected.splice(selectedIndex, 1);
238+
else selected.push(choice);
234239
}
235240
return selected;
236241
}
@@ -258,15 +263,18 @@ async function chooseMetadata(ui, body, defaults = {}) {
258263
])
259264
: false;
260265
if (useDefaults) return { topics: defaults.topics, projectId: defaults.projectId ?? null };
261-
const topics = await chooseTopics(ui, body, defaults.topics ?? suggestedTopics(body).slice(0, 1));
266+
const topics = await chooseTopics(ui, body, defaults.topics ?? []);
262267
const projectId = await chooseProject(ui, body, defaults.projectId ?? null);
263268
assertControlledMetadata(topics, projectId);
264269
return { topics, projectId };
265270
}
266271

267272
async function composeRecord(ui, { replyTarget = null, root = null } = {}) {
268273
let body = await ui.compose();
269-
if (!body) return;
274+
if (!body) {
275+
await showCancellation(ui);
276+
return;
277+
}
270278
let metadata = await chooseMetadata(ui, body, replyTarget ? {
271279
topics: replyTarget.data.topics ?? root?.data.topics,
272280
projectId: replyTarget.data.projectId ?? root?.data.projectId ?? null,
@@ -292,7 +300,8 @@ async function composeRecord(ui, { replyTarget = null, root = null } = {}) {
292300
'',
293301
`${color.dim}Konular: ${metadata.topics.map((topic) => TOPIC_NAMES[topic]).join(', ')}`,
294302
`Proje: ${metadata.projectId ? projectName(metadata.projectId) : 'yok'}`,
295-
`Dosya: ${path.relative(ROOT, candidate.file)}${color.reset}`,
303+
`Teknik ayrıntı · yerel hedef:`,
304+
` ${path.relative(ROOT, candidate.file)}${color.reset}`,
296305
'',
297306
'Ne yapalım?',
298307
].join('\n');
@@ -302,10 +311,17 @@ async function composeRecord(ui, { replyTarget = null, root = null } = {}) {
302311
{ label: 'Konu/projeyi değiştir', value: 'metadata' },
303312
{ label: 'Vazgeç', value: 'cancel' },
304313
]);
305-
if (action === 'cancel') return;
314+
if (action === 'cancel') {
315+
await showCancellation(ui);
316+
return;
317+
}
306318
if (action === 'body') {
307319
const revised = await ui.compose(body);
308-
if (revised) body = revised;
320+
if (!revised) {
321+
await showCancellation(ui);
322+
return;
323+
}
324+
body = revised;
309325
continue;
310326
}
311327
if (action === 'metadata') {
@@ -326,6 +342,13 @@ async function composeRecord(ui, { replyTarget = null, root = null } = {}) {
326342
}
327343
}
328344

345+
async function showCancellation(ui) {
346+
ui.clear();
347+
ui.header('İşlem iptal edildi');
348+
process.stdout.write(`${color.green}✓ Hiçbir kayıt oluşturulmadı.${color.reset}\n`);
349+
await ui.pause();
350+
}
351+
329352
async function postMenu(ui, root) {
330353
while (true) {
331354
const records = readAllPosts();
@@ -394,7 +417,7 @@ async function search(ui) {
394417
const root = record.data.replyTo ? rootPostForReplyTarget(records, record.data.replyTo) : record;
395418
if (root) matchingRoots.set(root.slug, root);
396419
}
397-
const root = await chooseRecord(ui, `Arama · “${query}”`, [...matchingRoots.values()]);
420+
const root = await chooseRecord(ui, `Gönderi ara · “${query}”`, [...matchingRoots.values()]);
398421
if (root) await postMenu(ui, root);
399422
}
400423

0 commit comments

Comments
 (0)