@slycode/slycode 0.2.4 → 0.2.6
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/data/scaffold-templates/seed-cards-existing.json +8 -0
- package/dist/data/scaffold-templates/seed-cards-new.json +8 -0
- package/dist/messaging/index.js +9 -2
- package/dist/messaging/index.js.map +1 -1
- package/dist/messaging/stt.d.ts +3 -1
- package/dist/messaging/stt.js +76 -0
- package/dist/messaging/stt.js.map +1 -1
- package/dist/messaging/types.d.ts +3 -1
- package/dist/scripts/scaffold.js +29 -7
- package/dist/web/.next/BUILD_ID +1 -1
- package/dist/web/.next/build-manifest.json +4 -4
- package/dist/web/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/dist/web/.next/server/app/_global-error/page.js +1 -1
- package/dist/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/_global-error.html +2 -2
- package/dist/web/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/dist/web/.next/server/app/_not-found/page.js +1 -1
- package/dist/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app/_not-found.html +1 -1
- package/dist/web/.next/server/app/_not-found.rsc +2 -2
- package/dist/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dist/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dist/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/.next/server/app/api/cli-assets/fix/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/fix/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/import/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/import/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/preview/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/preview/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/sync/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/sync/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/updates/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/updates/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/dashboard/route.js +1 -1
- package/dist/web/.next/server/app/api/dashboard/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/file/route.js +1 -1
- package/dist/web/.next/server/app/api/file/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/git-status/route.js +1 -1
- package/dist/web/.next/server/app/api/git-status/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/kanban/route.js +1 -1
- package/dist/web/.next/server/app/api/kanban/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/kanban/stream/route.js +1 -1
- package/dist/web/.next/server/app/api/kanban/stream/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/[id]/route.js +1 -1
- package/dist/web/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/reorder/route.js +1 -1
- package/dist/web/.next/server/app/api/projects/reorder/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/scheduler/route.js +1 -1
- package/dist/web/.next/server/app/api/scheduler/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/search/route.js +1 -1
- package/dist/web/.next/server/app/api/search/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/invalidate/route.js +1 -1
- package/dist/web/.next/server/app/api/sly-actions/invalidate/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/route.js +1 -1
- package/dist/web/.next/server/app/api/sly-actions/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/stream/route.js +1 -1
- package/dist/web/.next/server/app/api/sly-actions/stream/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/transcribe/route.js +5 -2
- package/dist/web/.next/server/app/api/transcribe/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/page/build-manifest.json +2 -2
- package/dist/web/.next/server/app/page.js +2 -2
- package/dist/web/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app/project/[id]/page/build-manifest.json +2 -2
- package/dist/web/.next/server/app/project/[id]/page.js +2 -2
- package/dist/web/.next/server/app/project/[id]/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/project/[id]/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/chunks/[externals]__c6831f39._.js +3 -0
- package/dist/web/.next/server/chunks/[externals]_node:async_hooks_b485b2a4._.js +3 -0
- package/dist/web/.next/server/chunks/[externals]_node:http_c3a9e25f._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__0234f869._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__0f8687da._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__104b2da3._.js +4 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__12f6cd6f._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__d219e3f0._.js → [root-of-the-server]__15fc9266._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__1cdc76ef._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__933e6077._.js → [root-of-the-server]__1ec21ccc._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__baa99257._.js → [root-of-the-server]__279e9bf3._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__46b023d4._.js → [root-of-the-server]__2d1f0ed9._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__3998d59e._.js +19 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__e9b0e744._.js → [root-of-the-server]__3c5ef8ec._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__3dc5531f._.js +5 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__403750fd._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__41df0777._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__b9e7d34c._.js → [root-of-the-server]__4244617a._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__949bb248._.js → [root-of-the-server]__47dd878e._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__bf286c26._.js → [root-of-the-server]__5e08b942._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__d38c7a96._.js → [root-of-the-server]__71bb3374._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__6d330d40._.js → [root-of-the-server]__7603305e._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__aa814a86._.js → [root-of-the-server]__7c476ad6._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__bbb4b3ac._.js → [root-of-the-server]__846ca56f._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__934c9bb4._.js +5 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__4d0d3464._.js → [root-of-the-server]__98d88050._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__4c7995bf._.js → [root-of-the-server]__b273cc05._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__bc55c42a._.js → [root-of-the-server]__d0f4efec._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__d6362272._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__ad64e04f._.js → [root-of-the-server]__de1277ee._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__e00fb85f._.js +9 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__e4988941._.js +4 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__f3e501b6._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__f1fe18e6._.js → [root-of-the-server]__f97e93fa._.js} +2 -2
- package/dist/web/.next/server/chunks/a9bf9_@aws-sdk_core_dist-es_submodules_protocols_json_AwsRestJsonProtocol_764d7a83.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_@aws-sdk_credential-provider-env_dist-es_index_55d96139.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_@aws-sdk_nested-clients_dist-es_submodules_signin_index_6712dec9.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_@aws-sdk_nested-clients_dist-es_submodules_sso-oidc_index_df09d547.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_@aws-sdk_nested-clients_dist-es_submodules_sts_index_c78619b3.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_@smithy_core_dist-es_submodules_event-streams_index_73e35402.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_ec9ae6c4._.js +18 -0
- package/dist/web/.next/server/chunks/src_677020aa._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__077f472c._.js +3 -0
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__977b1a68._.js → [root-of-the-server]__0841f0b5._.js} +2 -2
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__1f5fc489._.js +9 -0
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__2f64210a._.js +3 -0
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__d57c94e0._.js → [root-of-the-server]__92021d33._.js} +2 -2
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__e0032864._.js → [root-of-the-server]__9ac6ea25._.js} +2 -2
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__677b7660._.js → [root-of-the-server]__bcbe4bf2._.js} +2 -2
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__6db27fe1._.js → [root-of-the-server]__dfe2728c._.js} +2 -2
- package/dist/web/.next/server/chunks/ssr/src_components_Dashboard_tsx_efc4dc27._.js +1 -1
- package/dist/web/.next/server/middleware-build-manifest.js +2 -2
- package/dist/web/.next/server/pages/404.html +1 -1
- package/dist/web/.next/server/pages/500.html +2 -2
- package/dist/web/.next/static/chunks/0bab8c7c82cef548.js +4 -0
- package/dist/web/.next/static/chunks/{b694f741bb34ac84.js → 1b46e836090e130b.js} +1 -1
- package/dist/web/.next/static/chunks/{ef0dc6461e9250d8.js → cf910fc299170b7d.js} +2 -2
- package/dist/web/.next/static/chunks/de965b463aff71a9.js +1 -0
- package/dist/web/.next/static/chunks/f3d7065d54a0b9ac.css +1 -0
- package/dist/web/.next/static/chunks/{turbopack-4964158913ad5e72.js → turbopack-563e27abda63930f.js} +2 -2
- package/dist/web/package-lock.json +1589 -155
- package/dist/web/package.json +1 -0
- package/dist/web/src/app/api/transcribe/route.ts +96 -1
- package/dist/web/src/components/AddProjectModal.tsx +67 -35
- package/dist/web/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/templates/kanban-seed.json +1 -1
- package/dist/data/scaffold-templates/seed-cards.json +0 -20
- package/dist/web/.next/server/chunks/[externals]__65615fd8._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__884d73e4._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__8ab096a3._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__9058a007._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__f4124388._.js +0 -3
- package/dist/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_ffc6c790.js +0 -11
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__73cfc6bb._.js +0 -3
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__79c0188d._.js +0 -9
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__bb807bcf._.js +0 -3
- package/dist/web/.next/static/chunks/7660448872d80e27.js +0 -4
- package/dist/web/.next/static/chunks/f4999889f2006fea.css +0 -1
- package/dist/web/.next/static/chunks/fbbdd316640f1e15.js +0 -1
- /package/dist/web/.next/static/{sQ8knGS1B967Ng9HqMKOG → 2EjhdcgXP_G4Dc2aTnMhk}/_buildManifest.js +0 -0
- /package/dist/web/.next/static/{sQ8knGS1B967Ng9HqMKOG → 2EjhdcgXP_G4Dc2aTnMhk}/_clientMiddlewareManifest.json +0 -0
- /package/dist/web/.next/static/{sQ8knGS1B967Ng9HqMKOG → 2EjhdcgXP_G4Dc2aTnMhk}/_ssgManifest.js +0 -0
package/dist/web/package.json
CHANGED
|
@@ -4,8 +4,16 @@ import { promises as fs } from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { execFile } from 'child_process';
|
|
6
6
|
import { getSlycodeRoot } from '@/lib/paths';
|
|
7
|
+
import {
|
|
8
|
+
TranscribeStreamingClient,
|
|
9
|
+
StartStreamTranscriptionCommand,
|
|
10
|
+
type AudioStream,
|
|
11
|
+
type LanguageCode,
|
|
12
|
+
type MediaEncoding,
|
|
13
|
+
} from '@aws-sdk/client-transcribe-streaming';
|
|
7
14
|
|
|
8
15
|
let openaiClient: OpenAI | null = null;
|
|
16
|
+
let transcribeClient: TranscribeStreamingClient | null = null;
|
|
9
17
|
let envLoaded = false;
|
|
10
18
|
let envCache: Record<string, string> = {};
|
|
11
19
|
|
|
@@ -41,6 +49,13 @@ async function getClient(): Promise<OpenAI> {
|
|
|
41
49
|
return openaiClient;
|
|
42
50
|
}
|
|
43
51
|
|
|
52
|
+
function getTranscribeClient(region?: string): TranscribeStreamingClient {
|
|
53
|
+
if (!transcribeClient) {
|
|
54
|
+
transcribeClient = new TranscribeStreamingClient(region ? { region } : {});
|
|
55
|
+
}
|
|
56
|
+
return transcribeClient;
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
function execAsync(cmd: string, args: string[], options: Record<string, unknown>): Promise<string> {
|
|
45
60
|
return new Promise((resolve, reject) => {
|
|
46
61
|
execFile(cmd, args, { ...options, windowsHide: true }, (error, stdout, stderr) => {
|
|
@@ -76,6 +91,78 @@ async function transcribeLocal(audioBuffer: Buffer, ext: string, cliPath: string
|
|
|
76
91
|
}
|
|
77
92
|
}
|
|
78
93
|
|
|
94
|
+
async function transcribeAwsStreaming(audioBuffer: Buffer, ext: string, region: string, language: string): Promise<string> {
|
|
95
|
+
const client = getTranscribeClient(region || undefined);
|
|
96
|
+
|
|
97
|
+
const isOgg = ext === 'ogg' || ext === 'oga';
|
|
98
|
+
|
|
99
|
+
let streamBuffer: Buffer;
|
|
100
|
+
let mediaEncoding: MediaEncoding;
|
|
101
|
+
let sampleRate: number;
|
|
102
|
+
let pcmPath: string | null = null;
|
|
103
|
+
|
|
104
|
+
if (isOgg) {
|
|
105
|
+
// OGG/Opus can be sent directly
|
|
106
|
+
streamBuffer = audioBuffer;
|
|
107
|
+
mediaEncoding = 'ogg-opus';
|
|
108
|
+
sampleRate = 48000;
|
|
109
|
+
} else {
|
|
110
|
+
// Convert WebM/MP4 to PCM via ffmpeg
|
|
111
|
+
const tmpDir = process.env.TMPDIR || '/tmp';
|
|
112
|
+
const tmpFile = path.join(tmpDir, `transcribe_${Date.now()}.${ext}`);
|
|
113
|
+
pcmPath = tmpFile.replace(/\.[^.]+$/, '.pcm');
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await fs.writeFile(tmpFile, audioBuffer);
|
|
117
|
+
await execAsync('ffmpeg', [
|
|
118
|
+
'-i', tmpFile, '-ar', '16000', '-ac', '1', '-f', 's16le', '-y', pcmPath,
|
|
119
|
+
], { timeout: 30_000 });
|
|
120
|
+
streamBuffer = await fs.readFile(pcmPath);
|
|
121
|
+
await fs.unlink(tmpFile).catch(() => {});
|
|
122
|
+
} catch (err) {
|
|
123
|
+
await fs.unlink(tmpFile).catch(() => {});
|
|
124
|
+
throw new Error(`ffmpeg conversion to PCM failed: ${(err as Error).message}`);
|
|
125
|
+
}
|
|
126
|
+
mediaEncoding = 'pcm';
|
|
127
|
+
sampleRate = 16000;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const chunkSize = 4096;
|
|
131
|
+
async function* audioStream(): AsyncGenerator<AudioStream> {
|
|
132
|
+
for (let offset = 0; offset < streamBuffer.length; offset += chunkSize) {
|
|
133
|
+
yield { AudioEvent: { AudioChunk: streamBuffer.subarray(offset, offset + chunkSize) } };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const response = await client.send(new StartStreamTranscriptionCommand({
|
|
139
|
+
LanguageCode: language as LanguageCode,
|
|
140
|
+
MediaEncoding: mediaEncoding,
|
|
141
|
+
MediaSampleRateHertz: sampleRate,
|
|
142
|
+
AudioStream: audioStream(),
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
const parts: string[] = [];
|
|
146
|
+
if (response.TranscriptResultStream) {
|
|
147
|
+
for await (const event of response.TranscriptResultStream) {
|
|
148
|
+
if (event.TranscriptEvent?.Transcript?.Results) {
|
|
149
|
+
for (const result of event.TranscriptEvent.Transcript.Results) {
|
|
150
|
+
if (!result.IsPartial && result.Alternatives?.[0]?.Transcript) {
|
|
151
|
+
parts.push(result.Alternatives[0].Transcript);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return parts.join(' ').trim();
|
|
159
|
+
} finally {
|
|
160
|
+
if (pcmPath) {
|
|
161
|
+
await fs.unlink(pcmPath).catch(() => {});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
79
166
|
export async function POST(request: Request) {
|
|
80
167
|
try {
|
|
81
168
|
const formData = await request.formData();
|
|
@@ -102,7 +189,15 @@ export async function POST(request: Request) {
|
|
|
102
189
|
return NextResponse.json({ text });
|
|
103
190
|
}
|
|
104
191
|
|
|
105
|
-
|
|
192
|
+
if (backend === 'aws-transcribe') {
|
|
193
|
+
const region = process.env.AWS_TRANSCRIBE_REGION || env.AWS_TRANSCRIBE_REGION || '';
|
|
194
|
+
const language = process.env.AWS_TRANSCRIBE_LANGUAGE || env.AWS_TRANSCRIBE_LANGUAGE || 'en-AU';
|
|
195
|
+
|
|
196
|
+
const text = await transcribeAwsStreaming(buffer, ext, region, language);
|
|
197
|
+
return NextResponse.json({ text });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// OpenAI API path (default)
|
|
106
201
|
let client: OpenAI;
|
|
107
202
|
try {
|
|
108
203
|
client = await getClient();
|
|
@@ -15,6 +15,7 @@ interface AnalysisItem {
|
|
|
15
15
|
details?: { count?: number };
|
|
16
16
|
group?: string;
|
|
17
17
|
provider?: string;
|
|
18
|
+
essential?: boolean;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
interface AnalysisGroup {
|
|
@@ -598,7 +599,7 @@ export function AddProjectModal({ open, onClose, onCreated }: AddProjectModalPro
|
|
|
598
599
|
{/* Expanded items */}
|
|
599
600
|
{expanded && (
|
|
600
601
|
<div className="border-t border-void-700/50">
|
|
601
|
-
{group.items.map((item) => {
|
|
602
|
+
{[...group.items].sort((a, b) => (b.essential ? 1 : 0) - (a.essential ? 1 : 0)).map((item) => {
|
|
602
603
|
const action = itemActions[item.path] || 'skip';
|
|
603
604
|
const isMissing = item.status === 'missing';
|
|
604
605
|
const isPresent = item.status === 'present';
|
|
@@ -608,45 +609,64 @@ export function AddProjectModal({ open, onClose, onCreated }: AddProjectModalPro
|
|
|
608
609
|
return (
|
|
609
610
|
<div
|
|
610
611
|
key={item.path}
|
|
611
|
-
className=
|
|
612
|
+
className={`flex flex-col border-b border-void-700/30 px-3 py-1.5 last:border-0 ${item.essential ? 'bg-amber-900/10' : ''}`}
|
|
612
613
|
>
|
|
613
|
-
<div className="flex
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
614
|
+
<div className="flex items-center justify-between">
|
|
615
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
616
|
+
{isMissing && (
|
|
617
|
+
<span
|
|
618
|
+
className="flex-shrink-0 text-blue-400"
|
|
619
|
+
title="Will be created"
|
|
620
|
+
>
|
|
621
|
+
+
|
|
622
|
+
</span>
|
|
623
|
+
)}
|
|
624
|
+
{isPresent && (
|
|
625
|
+
<span
|
|
626
|
+
className="flex-shrink-0 text-green-400"
|
|
627
|
+
title={hasDifferentVersion ? `Local: ${item.localVersion}, Store: ${item.masterVersion}` : 'Up to date'}
|
|
628
|
+
>
|
|
629
|
+
✓
|
|
630
|
+
</span>
|
|
631
|
+
)}
|
|
632
|
+
<span className="truncate font-mono text-xs text-void-300">
|
|
633
|
+
{item.path}
|
|
620
634
|
</span>
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
635
|
+
{item.essential && (
|
|
636
|
+
<span className="flex-shrink-0 rounded-full bg-amber-500/20 px-1.5 py-0.5 text-[10px] font-medium text-amber-400">
|
|
637
|
+
Required
|
|
638
|
+
</span>
|
|
639
|
+
)}
|
|
640
|
+
{hasDifferentVersion && (
|
|
641
|
+
<span className="flex-shrink-0 text-xs text-void-600">
|
|
642
|
+
v{item.localVersion}
|
|
643
|
+
</span>
|
|
644
|
+
)}
|
|
645
|
+
</div>
|
|
646
|
+
{isMissing && (
|
|
647
|
+
<button
|
|
648
|
+
onClick={() => toggleAction(item.path)}
|
|
649
|
+
className={`flex-shrink-0 rounded px-2 py-0.5 text-xs font-medium ${
|
|
650
|
+
action === 'skip'
|
|
651
|
+
? 'bg-void-700 text-void-400'
|
|
652
|
+
: 'bg-blue-600/20 text-blue-400'
|
|
653
|
+
}`}
|
|
626
654
|
>
|
|
627
|
-
|
|
628
|
-
</
|
|
629
|
-
)}
|
|
630
|
-
<span className="truncate font-mono text-xs text-void-300">
|
|
631
|
-
{item.path}
|
|
632
|
-
</span>
|
|
633
|
-
{hasDifferentVersion && (
|
|
634
|
-
<span className="flex-shrink-0 text-xs text-void-600">
|
|
635
|
-
v{item.localVersion}
|
|
636
|
-
</span>
|
|
655
|
+
{action === 'skip' ? 'Skip' : 'Create'}
|
|
656
|
+
</button>
|
|
637
657
|
)}
|
|
638
658
|
</div>
|
|
639
|
-
{
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
>
|
|
648
|
-
|
|
649
|
-
</
|
|
659
|
+
{/* Warning when essential skill is skipped */}
|
|
660
|
+
{item.essential && isMissing && action === 'skip' && (
|
|
661
|
+
<p className="mt-1 text-[11px] text-amber-400/80">
|
|
662
|
+
SlyCode requires this skill to function properly.
|
|
663
|
+
</p>
|
|
664
|
+
)}
|
|
665
|
+
{/* Warning when essential skill already exists (may be overwritten by updates) */}
|
|
666
|
+
{item.essential && isPresent && (
|
|
667
|
+
<p className="mt-1 text-[11px] text-void-500">
|
|
668
|
+
Exists — will be kept. Updates are managed via CLI Assets.
|
|
669
|
+
</p>
|
|
650
670
|
)}
|
|
651
671
|
</div>
|
|
652
672
|
);
|
|
@@ -658,6 +678,18 @@ export function AddProjectModal({ open, onClose, onCreated }: AddProjectModalPro
|
|
|
658
678
|
})}
|
|
659
679
|
</div>
|
|
660
680
|
|
|
681
|
+
{/* Warning if essential skills are being skipped */}
|
|
682
|
+
{analysis.items.some(i => i.essential && i.status === 'missing' && itemActions[i.path] === 'skip') && (
|
|
683
|
+
<div className="rounded border border-amber-500/30 bg-amber-500/10 px-3 py-2">
|
|
684
|
+
<p className="text-xs font-medium text-amber-400">
|
|
685
|
+
Essential skills skipped
|
|
686
|
+
</p>
|
|
687
|
+
<p className="mt-0.5 text-[11px] text-amber-400/70">
|
|
688
|
+
Kanban and messaging skills are required for SlyCode's core functionality (card management, Telegram integration). The project will scaffold but some features won't work.
|
|
689
|
+
</p>
|
|
690
|
+
</div>
|
|
691
|
+
)}
|
|
692
|
+
|
|
661
693
|
<div className="flex justify-between pt-2">
|
|
662
694
|
<button
|
|
663
695
|
onClick={() => setPhase('providers')}
|