prosicht 1.2.0 → 1.3.0

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/README.md CHANGED
@@ -21,7 +21,20 @@ Güncelleme (şablon, `AGENTS.md` başındaki etiketten otomatik tespit edilir):
21
21
  ```bash
22
22
  npx prosicht update
23
23
  ```
24
- Sunum klasörlerinde `update` yalnızca çekirdek dosyaları yeniler; `scenes.js`, `sims/`, `styles/theme.css` ve `sources.md` dokunulmadan kalır.
24
+ Sunum klasörlerinde `update` yalnızca çekirdek dosyaları (`index.html`, `css/core/`, `js/core/`, `AGENTS.md`) yeniler; `js/scenes.js`, `js/sims/`, `css/theme.css`, `css/sims/`, `assets/` ve `sources.md` dokunulmadan kalır. Eski (1.x) klasör yapısındaki sunumlar onayla yeni yapıya taşınır (`--yes` sormadan taşır).
25
+
26
+ ## Yayınlama
27
+
28
+ ```bash
29
+ npx prosicht publish
30
+ ```
31
+ 1. deck.prosicht.com'da hesap açın ve **Yeni sunum ekle** ile 32 karakterlik bir key alın.
32
+ 2. Sunum klasöründe `npx prosicht publish` çalıştırın: **Sunum** → adres (varsayılan `deck.prosicht.com`) → key.
33
+ 3. Link terminalde verilir. Key ve adres isterseniz `.prosicht/publish.json` içine kaydedilir (git dışı); sonraki yayınlar sormaz.
34
+
35
+ Yalnızca `index.html`, `css/`, `js/` ve `assets/` yüklenir (en fazla 50 MB, dosya başına 25 MB, 500 dosya). `/` ile başlayan yollar için uyarı verilir. Kayıtlı key panelde yenilendiyse CLI yenisini sorar.
36
+
37
+ Seçenekler: `--key <key>`, `--host <url>`, `-y` (soruları atla).
25
38
 
26
39
  ## Sunum hazırlama
27
40
 
@@ -34,7 +47,7 @@ Ardından AI aracına konuyu söyleyin: *"KOBİ'ler için yapay zekâ konusunda
34
47
 
35
48
  ## Geliştirme
36
49
 
37
- Şablonları push etmeden yerel bir sunucudan denemek için:
50
+ Şablonları push etmeden yerel bir sunucudan denemek için (`PROSICHT_PUBLISH_URL` aynı şekilde yayın adresini değiştirir):
38
51
  ```bash
39
52
  cd ai-standards/templates && python3 -m http.server 8765
40
53
  PROSICHT_TEMPLATES_URL=http://127.0.0.1:8765 node /path/to/prosicht-cli/index.js init -t presentation
package/index.js CHANGED
@@ -5,6 +5,9 @@ const path = require('path');
5
5
  const { program } = require('commander');
6
6
  const prompts = require('prompts');
7
7
  const { version } = require('./package.json');
8
+ const { detectLayout } = require('./lib/layout');
9
+ const { migrateV1 } = require('./lib/migrate');
10
+ const { publish } = require('./lib/publish');
8
11
 
9
12
  // PROSICHT_TEMPLATES_URL: sablonlari push etmeden yerel bir sunucudan denemek icin
10
13
  const BASE_URL = (process.env.PROSICHT_TEMPLATES_URL || 'https://raw.githubusercontent.com/ProSicht/ai-standards/main/templates').replace(/\/+$/, '');
@@ -115,7 +118,17 @@ function resolveInsideCwd(relPath) {
115
118
 
116
119
  // init: çekirdek + başlangıç dosyaları (mevcut başlangıç dosyaları korunur)
117
120
  // update: yalnızca çekirdek dosyalar; sunum içeriğine dokunulmaz
118
- async function installPresentation(mode) {
121
+ async function confirmMigration() {
122
+ const response = await prompts({
123
+ type: 'confirm',
124
+ name: 'ok',
125
+ initial: true,
126
+ message: 'Bu sunum eski klasor yapisinda (kit 1.x). Yeni yapiya (index.html + css/ js/ assets/) tasinsin mi?'
127
+ });
128
+ return Boolean(response.ok);
129
+ }
130
+
131
+ async function installPresentation(mode, options = {}) {
119
132
  const base = `${BASE_URL}/${PRESENTATION.dir}`;
120
133
  console.log(`\n[Pro Sicht] Sunum altyapisi ${mode === 'update' ? 'guncelleniyor' : 'indiriliyor'}...`);
121
134
 
@@ -141,6 +154,16 @@ async function installPresentation(mode) {
141
154
  return { ...job, data };
142
155
  }));
143
156
 
157
+ // update: kit 1.x klasörünü önce yeni yapıya taşı (dosyalar indikten sonra, onayla).
158
+ // Yalnızca uzaktaki kit de yeni yapıdaysa: eski manifest eski yollara yazar.
159
+ if (mode === 'update' && detectLayout(process.cwd()) === 1 && Number(manifest.layout) >= 2) {
160
+ if (!options.yes && !(await confirmMigration())) {
161
+ console.log('Iptal edildi; hicbir dosya degistirilmedi.\n');
162
+ return;
163
+ }
164
+ migrateV1(process.cwd());
165
+ }
166
+
144
167
  for (const file of files) {
145
168
  fs.mkdirSync(path.dirname(file.target), { recursive: true });
146
169
  fs.writeFileSync(file.target, file.data);
@@ -152,9 +175,10 @@ async function installPresentation(mode) {
152
175
  if (mode === 'init') {
153
176
  console.log('\nSonraki adimlar:');
154
177
  console.log(' 1. python3 -m http.server 8000 -> http://localhost:8000 (ornek sunum)');
155
- console.log(' 2. AI aracina konuyu soyleyin: "<konu> hakkinda 10 dakikalik sunum hazirla"\n');
178
+ console.log(' 2. AI aracina konuyu soyleyin: "<konu> hakkinda 10 dakikalik sunum hazirla"');
179
+ console.log(' 3. npx prosicht publish -> deck.prosicht.com uzerinde yayinlayin\n');
156
180
  } else {
157
- console.log('Sunum icerigi (scenes.js, sims/, styles/theme.css, sources.md) degistirilmedi.\n');
181
+ console.log('Sunuma ait dosyalar (js/scenes.js, js/sims/, css/theme.css, css/sims/, assets/, sources.md) degistirilmedi.\n');
158
182
  }
159
183
  } catch (error) {
160
184
  console.error('Indirme hatasi:', error.message);
@@ -162,12 +186,12 @@ async function installPresentation(mode) {
162
186
  }
163
187
  }
164
188
 
165
- async function install(templateKey, mode) {
189
+ async function install(templateKey, mode, options = {}) {
166
190
  if (!TEMPLATE_KEYS.includes(templateKey)) {
167
191
  console.error(`Hata: Gecersiz sablon "${templateKey}". Gecerli: ${TEMPLATE_KEYS.join(', ')}`);
168
192
  process.exit(1);
169
193
  }
170
- if (templateKey === PRESENTATION.key) return installPresentation(mode);
194
+ if (templateKey === PRESENTATION.key) return installPresentation(mode, options);
171
195
  return fetchAndSaveTemplate(templateKey);
172
196
  }
173
197
 
@@ -195,6 +219,7 @@ program
195
219
  .command('update')
196
220
  .description('Projedeki AGENTS.md (ve sunum altyapisinin cekirdek dosyalarini) tespit edip gunceller')
197
221
  .option('-t, --template <type>', 'Sablon turunu zorla belirle')
222
+ .option('-y, --yes', 'Eski sunum yapisini sormadan yeni yapiya tasi')
198
223
  .action(async (options) => {
199
224
  let templateKey = options.template;
200
225
 
@@ -210,7 +235,15 @@ program
210
235
  }
211
236
  }
212
237
 
213
- await install(templateKey, 'update');
238
+ await install(templateKey, 'update', { yes: options.yes });
214
239
  });
215
240
 
241
+ program
242
+ .command('publish')
243
+ .description('Sunumu deck.prosicht.com uzerinde yayinlar ve linki verir')
244
+ .option('-k, --key <key>', 'Panelden alinan 32 karakterlik yayin keyi')
245
+ .option('--host <url>', 'Yayin adresi (varsayilan: https://deck.prosicht.com)')
246
+ .option('-y, --yes', 'Sorulari atla: Sunum secilir, key kaydedilir')
247
+ .action((options) => publish(options));
248
+
216
249
  program.parse(process.argv);
package/lib/files.js ADDED
@@ -0,0 +1,78 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // Yayına giden dosyalar: giriş noktası + üç klasör. Sunucu aynı kuralları uygular.
5
+ const PUBLISH_ROOTS = ['index.html', 'css', 'js', 'assets'];
6
+ const LIMITS = { totalBytes: 50 * 1024 * 1024, fileBytes: 25 * 1024 * 1024, files: 500 };
7
+
8
+ const MIME_TYPES = {
9
+ '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.mjs': 'text/javascript',
10
+ '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg',
11
+ '.jpeg': 'image/jpeg', '.webp': 'image/webp', '.avif': 'image/avif', '.gif': 'image/gif',
12
+ '.ico': 'image/x-icon', '.woff': 'font/woff', '.woff2': 'font/woff2', '.ttf': 'font/ttf',
13
+ '.otf': 'font/otf', '.mp4': 'video/mp4', '.webm': 'video/webm', '.mp3': 'audio/mpeg',
14
+ '.wav': 'audio/wav', '.ogg': 'audio/ogg', '.txt': 'text/plain', '.csv': 'text/csv', '.vtt': 'text/vtt'
15
+ };
16
+
17
+ function walk(root, rel, out) {
18
+ const abs = path.join(root, rel);
19
+ if (!fs.existsSync(abs)) return;
20
+ const stat = fs.lstatSync(abs);
21
+ if (stat.isSymbolicLink()) return;
22
+ if (stat.isFile()) {
23
+ out.push({ path: rel.split(path.sep).join('/'), abs, size: stat.size });
24
+ return;
25
+ }
26
+ for (const name of fs.readdirSync(abs).sort()) {
27
+ if (name.startsWith('.')) continue; // .gitkeep, .DS_Store
28
+ walk(root, path.join(rel, name), out);
29
+ }
30
+ }
31
+
32
+ // Yayınlanacak dosyaları toplar ve kurallara göre denetler
33
+ function collectFiles(root) {
34
+ const files = [];
35
+ for (const entry of PUBLISH_ROOTS) walk(root, entry, files);
36
+ const errors = [];
37
+ if (!files.some((f) => f.path === 'index.html')) errors.push('index.html bulunamadi (giris noktasi zorunlu)');
38
+ for (const f of files) {
39
+ const ext = path.extname(f.path).toLowerCase();
40
+ if (!MIME_TYPES[ext]) errors.push(`${f.path}: izin verilmeyen dosya turu`);
41
+ else if (ext === '.html' && f.path !== 'index.html') errors.push(`${f.path}: yalnizca kokteki index.html yayinlanir`);
42
+ if (f.size > LIMITS.fileBytes) errors.push(`${f.path}: dosya 25 MB sinirini asiyor`);
43
+ }
44
+ const total = files.reduce((sum, f) => sum + f.size, 0);
45
+ if (files.length > LIMITS.files) errors.push(`${files.length} dosya: en fazla ${LIMITS.files}`);
46
+ if (total > LIMITS.totalBytes) errors.push(`toplam ${formatBytes(total)}: en fazla 50 MB`);
47
+ return { files, total, errors };
48
+ }
49
+
50
+ // Yayında alt yolda servis edildiği için / ile başlayan yollar kırılır
51
+ function findAbsolutePaths(files) {
52
+ const pattern = /(?:\b(?:src|href)\s*=\s*["']|url\(\s*["']?|\bfrom\s+["']|\bimport\(\s*["'])\/(?!\/)/;
53
+ const hits = [];
54
+ for (const f of files) {
55
+ if (!/\.(html|css|m?js)$/.test(f.path)) continue;
56
+ const lines = fs.readFileSync(f.abs, 'utf8').split('\n');
57
+ lines.forEach((line, i) => { if (pattern.test(line)) hits.push(`${f.path}:${i + 1}`); });
58
+ }
59
+ return hits;
60
+ }
61
+
62
+ // js/scenes.js içindeki deck.title (panelde ve paylaşım önizlemesinde görünür)
63
+ function readDeckTitle(root) {
64
+ const file = path.join(root, 'js', 'scenes.js');
65
+ if (!fs.existsSync(file)) return null;
66
+ const source = fs.readFileSync(file, 'utf8');
67
+ const deck = source.match(/export\s+const\s+deck\s*=\s*\{([\s\S]*?)\};/);
68
+ const title = deck && deck[1].match(/\btitle\s*:\s*(['"`])((?:(?!\1).)*)\1/);
69
+ return title ? title[2].trim().slice(0, 120) : null;
70
+ }
71
+
72
+ function formatBytes(n) {
73
+ if (n < 1024) return `${n} B`;
74
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;
75
+ return `${(n / 1024 / 1024).toFixed(1)} MB`;
76
+ }
77
+
78
+ module.exports = { collectFiles, findAbsolutePaths, readDeckTitle, formatBytes, MIME_TYPES };
package/lib/layout.js ADDED
@@ -0,0 +1,23 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // Sunum klasör yapıları: 1 = kök dizinde app.js/sims/styles (kit 1.x),
5
+ // 2 = index.html + css/ js/ assets/ (kit 2.x). 0 = sunum değil.
6
+ function detectLayout(root) {
7
+ const has = (rel) => fs.existsSync(path.join(root, rel));
8
+ if (has('js/core/app.js')) return 2;
9
+ if (has('app.js') && has('sims/engine.js')) return 1;
10
+ return 0;
11
+ }
12
+
13
+ // Proje klasöründeki .gitignore'a satır ekler (yoksa oluşturur)
14
+ function ensureGitignore(root, line) {
15
+ const file = path.join(root, '.gitignore');
16
+ const current = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
17
+ if (current.split(/\r?\n/).some((l) => l.trim() === line)) return false;
18
+ const prefix = current && !current.endsWith('\n') ? '\n' : '';
19
+ fs.writeFileSync(file, `${current}${prefix}${line}\n`, 'utf8');
20
+ return true;
21
+ }
22
+
23
+ module.exports = { detectLayout, ensureGitignore };
package/lib/migrate.js ADDED
@@ -0,0 +1,72 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { ensureGitignore } = require('./layout');
4
+
5
+ // Kit 1.x çekirdek dosyaları: 2.x'te js/core/ ve css/core/ altına taşındı,
6
+ // update yenilerini indirdiği için eskileri silinir
7
+ const OLD_CORE = ['app.js', 'sound.js', 'sims/engine.js', 'sims/kit.js', 'styles/shell.css'];
8
+
9
+ // Sunuma ait dosyaların 1.x -> 2.x taşıma planı
10
+ function planMoves(root) {
11
+ const moves = [
12
+ { from: 'scenes.js', to: 'js/scenes.js' },
13
+ { from: 'styles/theme.css', to: 'css/theme.css' }
14
+ ];
15
+ const simsDir = path.join(root, 'sims');
16
+ if (fs.existsSync(simsDir)) {
17
+ for (const name of fs.readdirSync(simsDir)) {
18
+ if (name === 'engine.js' || name === 'kit.js') continue;
19
+ if (name.endsWith('.js')) moves.push({ from: `sims/${name}`, to: `js/sims/${name}`, rewrite: true });
20
+ else if (name.endsWith('.css')) moves.push({ from: `sims/${name}`, to: `css/sims/${name}` });
21
+ }
22
+ }
23
+ return moves.filter((m) => fs.existsSync(path.join(root, m.from)));
24
+ }
25
+
26
+ // Taşınan sim dosyalarında göreli yolları yeni konuma göre düzeltir
27
+ function rewriteSim(source) {
28
+ return source
29
+ .replace(/(['"])\.\/engine\.js\1/g, '$1../core/engine.js$1')
30
+ .replace(/(['"])\.\/kit\.js\1/g, '$1../core/kit.js$1')
31
+ .replace(/(['"`])\.\.\/assets\//g, '$1../../assets/');
32
+ }
33
+
34
+ function removeIfEmpty(dir) {
35
+ if (fs.existsSync(dir) && fs.readdirSync(dir).filter((n) => n !== '.DS_Store').length === 0) {
36
+ fs.rmSync(dir, { recursive: true, force: true });
37
+ }
38
+ }
39
+
40
+ // 1.x sunum klasörünü 2.x yapısına taşır; yapılan her işlemi yazdırır
41
+ function migrateV1(root) {
42
+ console.log('\n[Pro Sicht] Sunum yeni klasor yapisina tasiniyor...');
43
+ for (const move of planMoves(root)) {
44
+ const from = path.join(root, move.from);
45
+ const to = path.join(root, move.to);
46
+ if (fs.existsSync(to)) {
47
+ console.log(` ! ${move.to} zaten var, ${move.from} yerinde birakildi`);
48
+ continue;
49
+ }
50
+ fs.mkdirSync(path.dirname(to), { recursive: true });
51
+ if (move.rewrite) {
52
+ fs.writeFileSync(to, rewriteSim(fs.readFileSync(from, 'utf8')), 'utf8');
53
+ fs.rmSync(from);
54
+ } else {
55
+ fs.renameSync(from, to);
56
+ }
57
+ console.log(` > ${move.from} -> ${move.to}`);
58
+ }
59
+ for (const rel of OLD_CORE) {
60
+ const file = path.join(root, rel);
61
+ if (fs.existsSync(file)) {
62
+ fs.rmSync(file);
63
+ console.log(` - ${rel} (eski cekirdek dosyasi)`);
64
+ }
65
+ }
66
+ removeIfEmpty(path.join(root, 'sims'));
67
+ removeIfEmpty(path.join(root, 'styles'));
68
+ fs.mkdirSync(path.join(root, 'assets'), { recursive: true });
69
+ if (ensureGitignore(root, '.prosicht/')) console.log(' + .gitignore (.prosicht/)');
70
+ }
71
+
72
+ module.exports = { migrateV1, planMoves, rewriteSim };
package/lib/publish.js ADDED
@@ -0,0 +1,171 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const prompts = require('prompts');
4
+ const { detectLayout, ensureGitignore } = require('./layout');
5
+ const { collectFiles, findAbsolutePaths, readDeckTitle, formatBytes, MIME_TYPES } = require('./files');
6
+
7
+ const DEFAULT_HOST = (process.env.PROSICHT_PUBLISH_URL || 'https://deck.prosicht.com').replace(/\/+$/, '');
8
+ const KEY_PATTERN = /^[A-Za-z0-9]{32}$/;
9
+ const CONFIG_FILE = path.join('.prosicht', 'publish.json');
10
+
11
+ function fail(message, details = []) {
12
+ console.error(`\nHata: ${message}`);
13
+ for (const line of details) console.error(` - ${line}`);
14
+ process.exit(1);
15
+ }
16
+
17
+ function readConfig(root) {
18
+ try {
19
+ const data = JSON.parse(fs.readFileSync(path.join(root, CONFIG_FILE), 'utf8'));
20
+ return data && typeof data === 'object' ? data : {};
21
+ } catch {
22
+ return {};
23
+ }
24
+ }
25
+
26
+ // Key yalnızca bu klasörde, git'e girmeyen .prosicht/ altında tutulur
27
+ function saveConfig(root, config) {
28
+ const file = path.join(root, CONFIG_FILE);
29
+ fs.mkdirSync(path.dirname(file), { recursive: true });
30
+ fs.writeFileSync(file, JSON.stringify(config, null, 2) + '\n', { encoding: 'utf8', mode: 0o600 });
31
+ ensureGitignore(root, '.prosicht/');
32
+ }
33
+
34
+ function normalizeHost(value) {
35
+ const raw = String(value || '').trim().replace(/\/+$/, '');
36
+ const url = /^https?:\/\//.test(raw) ? raw : `https://${raw}`;
37
+ try {
38
+ const parsed = new URL(url);
39
+ return `${parsed.protocol}//${parsed.host}`;
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ async function ask(question) {
46
+ const answer = await prompts(question, { onCancel: () => process.exit(0) });
47
+ return answer[question.name];
48
+ }
49
+
50
+ async function chooseHost(saved, flag) {
51
+ if (flag) return normalizeHost(flag) || fail(`Gecersiz adres: ${flag}`);
52
+ if (saved) return saved;
53
+ const choice = await ask({
54
+ type: 'select', name: 'host', message: 'Yayin adresi',
55
+ choices: [
56
+ { title: `${DEFAULT_HOST.replace(/^https?:\/\//, '')} (varsayilan)`, value: DEFAULT_HOST },
57
+ { title: 'Baska bir adres', value: 'custom' }
58
+ ]
59
+ });
60
+ if (choice !== 'custom') return choice;
61
+ const custom = await ask({ type: 'text', name: 'url', message: 'Adres (or. https://deck.prosicht.com)', validate: (v) => (normalizeHost(v) ? true : 'Gecerli bir adres girin') });
62
+ return normalizeHost(custom);
63
+ }
64
+
65
+ async function chooseKey(saved, flag) {
66
+ if (flag) return KEY_PATTERN.test(flag) ? flag : fail('Key 32 karakter olmali (harf ve rakam).');
67
+ if (saved && KEY_PATTERN.test(saved)) {
68
+ console.log(`Kayitli key kullaniliyor (....${saved.slice(-4)}). Degistirmek icin: --key`);
69
+ return saved;
70
+ }
71
+ return ask({
72
+ type: 'password', name: 'key', message: 'Lutfen keyi giriniz',
73
+ validate: (v) => (KEY_PATTERN.test(String(v).trim()) ? true : 'Key 32 karakter olmali (harf ve rakam)'),
74
+ format: (v) => String(v).trim()
75
+ });
76
+ }
77
+
78
+ async function upload(host, key, files, title) {
79
+ const form = new FormData();
80
+ form.append('manifest', JSON.stringify({ title, files: files.map((f) => ({ path: f.path, size: f.size })) }));
81
+ for (const f of files) {
82
+ const type = MIME_TYPES[path.extname(f.path).toLowerCase()];
83
+ form.append('files', new Blob([fs.readFileSync(f.abs)], { type }), path.basename(f.path));
84
+ }
85
+ const { version } = require('../package.json');
86
+ const response = await fetch(`${host}/api/publish`, {
87
+ method: 'POST',
88
+ headers: { Authorization: `Bearer ${key}`, 'User-Agent': `prosicht-cli/${version}` },
89
+ body: form
90
+ });
91
+ let body = {};
92
+ try { body = await response.json(); } catch { /* HTML error page from a proxy */ }
93
+ return { status: response.status, body };
94
+ }
95
+
96
+ function explain(status, body) {
97
+ if (status === 401) fail('Key gecersiz veya yenilenmis. Panelden guncel keyi alin.');
98
+ if (status === 413) fail('Sunum boyut sinirini asiyor (en fazla 50 MB).');
99
+ if (status === 400 || status === 422) fail(body.error || 'Dosyalar reddedildi.', body.details || []);
100
+ fail(`Sunucu hatasi (HTTP ${status})${body.error ? `: ${body.error}` : ''}`);
101
+ }
102
+
103
+ async function publish(options = {}) {
104
+ const root = process.cwd();
105
+
106
+ const kind = options.yes ? 'presentation' : await ask({
107
+ type: 'select', name: 'kind', message: 'Ne yayinlamak istiyorsunuz?',
108
+ choices: [
109
+ { title: 'Sunum', value: 'presentation' },
110
+ { title: 'Uygulama', value: 'app', disabled: true, description: 'yakinda' }
111
+ ]
112
+ });
113
+ if (kind !== 'presentation') process.exit(0);
114
+
115
+ const layout = detectLayout(root);
116
+ if (layout === 1) fail('Bu sunum eski klasor yapisinda. Once `npx prosicht update` ile yeni yapiya tasiyin.');
117
+ if (layout === 0) fail('Bu klasorde bir sunum bulunamadi (index.html ve js/core/app.js gerekli). Sunum klasorunde calistirin.');
118
+
119
+ const { files, total, errors } = collectFiles(root);
120
+ if (errors.length) fail('Yayin oncesi kontrol basarisiz:', errors);
121
+ const absolute = findAbsolutePaths(files);
122
+ if (absolute.length) {
123
+ console.log('\nUyari: "/" ile baslayan yollar yayinda calismaz (goreli yol kullanin):');
124
+ for (const hit of absolute.slice(0, 10)) console.log(` - ${hit}`);
125
+ }
126
+
127
+ const config = readConfig(root);
128
+ const host = await chooseHost(options.host ? null : config.host, options.host);
129
+ let key = await chooseKey(options.key ? null : config.key, options.key);
130
+ if (!key) process.exit(0);
131
+
132
+ const title = readDeckTitle(root);
133
+ const send = async () => {
134
+ console.log(`\n[Pro Sicht] ${files.length} dosya (${formatBytes(total)}) yukleniyor...`);
135
+ try {
136
+ return await upload(host, key, files, title);
137
+ } catch (error) {
138
+ return fail(`${host} adresine ulasilamadi: ${error.cause?.code || error.message}`);
139
+ }
140
+ };
141
+ let result = await send();
142
+ // kayıtlı key panelden yenilenmişse bir kez yenisini sor ve tekrar dene
143
+ if (result.status === 401 && key === config.key && !options.key && !options.yes) {
144
+ console.log('Kayitli key gecersiz; panelde yenilenmis olabilir.');
145
+ key = await chooseKey(null, null);
146
+ if (!key) process.exit(0);
147
+ result = await send();
148
+ }
149
+ if (result.status !== 200 || !result.body.url) explain(result.status, result.body);
150
+
151
+ const { url, privacy, version } = result.body;
152
+ console.log(`Yayinlandi (surum ${version}): ${url}`);
153
+ if (privacy === 'private') {
154
+ console.log('Gizlilik: yalnizca siz gorebilirsiniz. Paylasmak icin panelden "Baglantiya sahip herkes" secin.');
155
+ } else {
156
+ console.log('Gizlilik: baglantiya sahip herkes gorebilir.');
157
+ }
158
+
159
+ if (config.key !== key || config.host !== host) {
160
+ const remember = options.yes ? true : await ask({
161
+ type: 'confirm', name: 'save', initial: true,
162
+ message: 'Key ve adres bu klasor icin kaydedilsin mi? (.prosicht/, git disi)'
163
+ });
164
+ if (remember) saveConfig(root, { host, key, deckId: result.body.deckId, url });
165
+ } else {
166
+ saveConfig(root, { ...config, deckId: result.body.deckId, url });
167
+ }
168
+ console.log('');
169
+ }
170
+
171
+ module.exports = { publish };
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "prosicht",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Pro Sicht AI Standards CLI: AGENTS.md sablonlari ve sunum altyapisi",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "prosicht": "./index.js"
8
8
  },
9
9
  "files": [
10
- "index.js"
10
+ "index.js",
11
+ "lib/"
11
12
  ],
12
13
  "engines": {
13
14
  "node": ">=18"