slacklocalvibe 0.1.4 → 0.1.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/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # SlackLocalVibe
1
+ # SlackLocalVibe for Codex / ClaudeCode
2
2
 
3
- Slack DM 通知と「返信 → CLI resume」をつなぐローカルブリッジです。
4
- Codex / Claude Code の完了通知を Slack に送り、スレッド返信で resume を実行します。
3
+ ## 機能
4
+
5
+ - Codex / ClaudeCode の結果を Slack DM に通知
6
+ - Slack スレッド返信を CLI resume として実行
5
7
 
6
8
  ## 必要環境
7
9
 
@@ -10,31 +12,15 @@ Codex / Claude Code の完了通知を Slack に送り、スレッド返信で r
10
12
 
11
13
  ## インストール
12
14
 
13
- ユーザーが実行するのはこれだけです(初回セットアップ)。
14
-
15
- ```bash
16
- npx slacklocalvibe
17
- ```
18
-
19
- ウィザード内で `npm i -g slacklocalvibe` を実行し、以降の返信/常駐でグローバルコマンドを使います。
20
-
21
- ## 使い方
22
-
23
- セットアップウィザードを起動します。
15
+ ユーザーが実行するのはこれだけです。(セットアップ・アップデート・テスト)
16
+ ウィザード内で `npm i -g slacklocalvibe` を実行します。
24
17
 
25
18
  ```bash
26
19
  npx slacklocalvibe
27
20
  ```
28
21
 
29
- ### サブコマンド
30
-
31
- - 通知: `slacklocalvibe notify --tool codex|claude`
32
- - daemon: `slacklocalvibe daemon`
33
- - launchd: `slacklocalvibe launchd install|uninstall|status`
34
-
35
- launchd は **グローバル固定**です。
36
-
37
22
  ## 設定・ログ
38
23
 
39
24
  - 設定: `~/.config/slacklocalvibe/config.json`
40
25
  - ログ: `~/Library/Logs/slacklocalvibe/`
26
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slacklocalvibe",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "SlackLocalVibe: Codex/Claude Code turn notifications and reply→resume bridge for Slack DM (Socket Mode)",
5
5
  "bin": {
6
6
  "slacklocalvibe": "src/cli.js"
@@ -2,6 +2,21 @@ const fs = require("fs");
2
2
  const os = require("os");
3
3
  const path = require("path");
4
4
 
5
+ const CODEX_INTERNAL_TITLE_PROMPT_PREFIX =
6
+ "You are a helpful assistant. You will be presented with a user prompt";
7
+ const CODEX_INTERNAL_TITLE_PROMPT_LINES = [
8
+ "Generate a concise UI title (18-36 characters) for this task.",
9
+ "Return only the title. No quotes or trailing punctuation.",
10
+ "Do not use markdown or formatting characters.",
11
+ "If the task includes a ticket reference (e.g. ABC-123), include it verbatim.",
12
+ "Generate a clear, informative task title based solely on the prompt provided. Follow the rules below to ensure consistency, readability, and usefulness.",
13
+ "How to write a good title:",
14
+ "Generate a single-line title that captures the question or core change requested. The title should be easy to scan and useful in changelogs or review queues.",
15
+ "By following these conventions, your titles will be readable, changelog-friendly, and helpful to both users and downstream tools.",
16
+ "Examples:",
17
+ ];
18
+ const CODEX_INTERNAL_TITLE_PROMPT_MIN_MATCHES = 3;
19
+
5
20
  function parseCodexNotify(rawJson) {
6
21
  const payload = JSON.parse(rawJson);
7
22
  if (payload?.type !== "agent-turn-complete") {
@@ -13,17 +28,23 @@ function parseCodexNotify(rawJson) {
13
28
  const meta = buildCodexInputMeta(inputMessages);
14
29
  const codexHomeInfo = resolveCodexHomeInfo();
15
30
  Object.assign(meta, codexHomeInfo.meta || {});
16
- if (codexHomeInfo.isDefault) {
31
+ const rolloutResult = readCodexUserMessageFromRollout(sessionId, codexHomeInfo.home);
32
+ Object.assign(meta, rolloutResult.meta || {});
33
+ const userText = rolloutResult.userText || "";
34
+ const internalPromptCheck = matchCodexInternalTitlePrompt(userText);
35
+ Object.assign(meta, {
36
+ codex_internal_title_prompt_match: internalPromptCheck.match,
37
+ codex_internal_title_prompt_hits: internalPromptCheck.hits,
38
+ codex_internal_title_prompt_first_line: internalPromptCheck.firstLine,
39
+ });
40
+ if (internalPromptCheck.match) {
17
41
  return {
18
42
  tool: "codex",
19
43
  skip: true,
20
- skip_reason: "codex_home_default",
44
+ skip_reason: "codex_internal_title_prompt",
21
45
  meta,
22
46
  };
23
47
  }
24
- const rolloutResult = readCodexUserMessageFromRollout(sessionId, codexHomeInfo.home);
25
- Object.assign(meta, rolloutResult.meta || {});
26
- const userText = rolloutResult.userText || "";
27
48
  const assistantText = extractAssistantText(payload["last-assistant-message"]);
28
49
  const cwd = payload?.cwd ? String(payload.cwd) : "";
29
50
 
@@ -78,6 +99,34 @@ function extractAssistantText(content) {
78
99
  return normalizeContent(content);
79
100
  }
80
101
 
102
+ function matchCodexInternalTitlePrompt(text) {
103
+ const firstLine = firstNonEmptyLine(text);
104
+ if (!firstLine.startsWith(CODEX_INTERNAL_TITLE_PROMPT_PREFIX)) {
105
+ return { match: false, hits: 0, firstLine };
106
+ }
107
+ let hits = 0;
108
+ for (const line of CODEX_INTERNAL_TITLE_PROMPT_LINES) {
109
+ if (text.includes(line)) {
110
+ hits += 1;
111
+ }
112
+ }
113
+ return {
114
+ match: hits >= CODEX_INTERNAL_TITLE_PROMPT_MIN_MATCHES,
115
+ hits,
116
+ firstLine,
117
+ };
118
+ }
119
+
120
+ function firstNonEmptyLine(text) {
121
+ if (!text) return "";
122
+ const lines = String(text).split(/\r?\n/);
123
+ for (const line of lines) {
124
+ const trimmed = line.trim();
125
+ if (trimmed) return trimmed;
126
+ }
127
+ return "";
128
+ }
129
+
81
130
  function readCodexUserMessageFromRollout(sessionId, codexHome) {
82
131
  const meta = {
83
132
  codex_rollout_found: false,