@yeaft/webchat-agent 0.1.246 → 0.1.248

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.
@@ -12,7 +12,7 @@ import {
12
12
  createConversation, resumeConversation, deleteConversation,
13
13
  handleRefreshConversation, handleCancelExecution,
14
14
  handleUserInput, handleUpdateConversationSettings, handleAskUserAnswer,
15
- sendConversationList, handleBtwQuestion
15
+ sendConversationList, handleBtwQuestion, preloadSlashCommands
16
16
  } from '../conversation.js';
17
17
  import {
18
18
  createCrewSession, handleCrewHumanInput, handleCrewControl,
@@ -65,6 +65,9 @@ export async function handleMessage(msg) {
65
65
  if (ctx.mcpServers.length > 0) {
66
66
  sendToServer({ type: 'mcp_servers_list', servers: ctx.mcpServers });
67
67
  }
68
+
69
+ // ★ Preload slash commands for immediate skill availability in new sessions
70
+ preloadSlashCommands().catch(() => {});
68
71
  break;
69
72
 
70
73
  case 'create_conversation':
package/conversation.js CHANGED
@@ -21,6 +21,58 @@ function prestartClaude(conversationId, workDir, resumeSessionId) {
21
21
  });
22
22
  }
23
23
 
24
+ /**
25
+ * Preload slash commands from Claude CLI (fire-and-forget).
26
+ * Spawns a minimal CLI process with a cheap built-in command (/cost)
27
+ * to trigger the system init message, captures slash_commands,
28
+ * then aborts immediately (no API tokens consumed).
29
+ *
30
+ * @param {string} [workDir] - Project directory (default: agent workDir)
31
+ * @param {string} [targetId] - conversationId to key the update to
32
+ * ('__preload__' for agent-level, or crewSessionId)
33
+ */
34
+ export async function preloadSlashCommands(workDir, targetId = '__preload__') {
35
+ const effectiveWorkDir = workDir || ctx.CONFIG.workDir;
36
+ try {
37
+ const abortController = new AbortController();
38
+ // Use --print with a cheap built-in command to trigger system init.
39
+ // In stream-json mode, Claude CLI won't emit init until a user message arrives,
40
+ // so we use string prompt mode instead which triggers init immediately.
41
+ const claudeQuery = query({
42
+ prompt: '/cost',
43
+ options: {
44
+ cwd: effectiveWorkDir,
45
+ permissionMode: 'bypassPermissions',
46
+ abort: abortController.signal,
47
+ maxTurns: 1
48
+ }
49
+ });
50
+ for await (const message of claudeQuery) {
51
+ if (message.type === 'system' && message.subtype === 'init') {
52
+ const slashCommands = message.slash_commands || [];
53
+ if (slashCommands.length > 0) {
54
+ // Update agent-level cache if this is the first load
55
+ if (ctx.slashCommands.length === 0) {
56
+ ctx.slashCommands = [...slashCommands];
57
+ }
58
+ ctx.sendToServer({
59
+ type: 'slash_commands_update',
60
+ conversationId: targetId,
61
+ slashCommands
62
+ });
63
+ console.log(`[Preload] ${targetId}: loaded ${slashCommands.length} slash commands from ${effectiveWorkDir}`);
64
+ }
65
+ abortController.abort();
66
+ break;
67
+ }
68
+ }
69
+ } catch (err) {
70
+ if (err.name !== 'AbortError') {
71
+ console.warn(`[Preload] Failed for ${targetId}: ${err.message}`);
72
+ }
73
+ }
74
+ }
75
+
24
76
  /**
25
77
  * 解析斜杠命令
26
78
  * @param {string} message - 用户消息
package/crew/session.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  loadSessionMeta, saveSessionMeta, loadSessionMessages, getMaxShardIndex
13
13
  } from './persistence.js';
14
14
  import { sendCrewMessage, sendCrewOutput, sendStatusUpdate } from './ui-messages.js';
15
+ import { preloadSlashCommands } from '../conversation.js';
15
16
 
16
17
  // =====================================================================
17
18
  // Data Structures
@@ -295,6 +296,9 @@ export async function createCrewSession(msg) {
295
296
  });
296
297
  }
297
298
 
299
+ // ★ Preload project-level skills for crew session input autocomplete
300
+ preloadSlashCommands(projectDir, sessionId).catch(() => {});
301
+
298
302
  return session;
299
303
  }
300
304
 
@@ -463,6 +467,8 @@ export async function resumeCrewSession(msg) {
463
467
  hasOlderMessages
464
468
  });
465
469
  sendStatusUpdate(session);
470
+ // ★ Preload project-level skills for crew session input autocomplete
471
+ preloadSlashCommands(session.projectDir, sessionId).catch(() => {});
466
472
  return;
467
473
  }
468
474
 
@@ -540,6 +546,9 @@ export async function resumeCrewSession(msg) {
540
546
  await upsertCrewIndex(session);
541
547
  await saveSessionMeta(session);
542
548
 
549
+ // ★ Preload project-level skills for crew session input autocomplete
550
+ preloadSlashCommands(session.projectDir, sessionId).catch(() => {});
551
+
543
552
  console.log(`[Crew] Session ${sessionId} resumed, waiting for human input`);
544
553
  }
545
554
 
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import 'dotenv/config';
2
2
  import { platform, homedir } from 'os';
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync } from 'fs';
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, chmodSync, readdirSync } from 'fs';
4
4
  import { join, dirname } from 'path';
5
5
  import { exec } from 'child_process';
6
6
  import { promisify } from 'util';
@@ -217,10 +217,22 @@ async function ensureYeaftSkills() {
217
217
  writeFileSync(knownFile, JSON.stringify(known, null, 2));
218
218
  }
219
219
 
220
+ // --- Layer 2.5: Ensure hook scripts are executable (git clone may lose +x on some OS) ---
221
+ const fixHookPermissions = (dir) => {
222
+ const hooksDir = join(dir, 'hooks');
223
+ if (existsSync(hooksDir)) {
224
+ for (const f of readdirSync(hooksDir)) {
225
+ try { chmodSync(join(hooksDir, f), 0o755); } catch { /* ignore */ }
226
+ }
227
+ }
228
+ };
229
+ fixHookPermissions(installDir);
230
+
220
231
  // --- Layer 3: Copy to plugin cache (on first install or after update) ---
221
232
  if (!existsSync(cacheDir) || needsCacheUpdate) {
222
233
  mkdirSync(cacheDir, { recursive: true });
223
234
  cpSync(installDir, cacheDir, { recursive: true });
235
+ fixHookPermissions(cacheDir);
224
236
  console.log(`[Startup] yeaft-skills ${needsCacheUpdate ? 'updated in' : 'copied to'} plugin cache`);
225
237
  }
226
238
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.246",
3
+ "version": "0.1.248",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",