@hienlh/ppm 0.9.10 → 0.9.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.9.10",
3
+ "version": "0.9.12",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bun
2
+ // PPM CLI entry point — Bun runtime, Hono backend, React frontend, Claude Agent SDK for AI chat
2
3
  import { Command } from "commander";
3
4
  import { VERSION } from "./version.ts";
4
5
 
@@ -266,13 +266,16 @@ async function startSessionConsumer(sessionId: string, providerId: string, conte
266
266
  // Track TeamCreate calls for team detection
267
267
  if (ev.tool === "TeamCreate") {
268
268
  entry.pendingTeamCreate = ev.toolUseId;
269
+ console.log(`[chat] session=${sessionId} TeamCreate tool_use detected, toolUseId=${ev.toolUseId}`);
269
270
  }
270
271
  } else if (evType === "tool_result") {
271
272
  logSessionEvent(sessionId, "TOOL_RESULT", `error=${ev.isError ?? false} ${(ev.output ?? "").slice(0, 300)}`);
273
+ console.log(`[chat] session=${sessionId} tool_result: toolUseId=${ev.toolUseId} pendingTeamCreate=${entry.pendingTeamCreate} output=${(ev.output ?? "").slice(0, 200)}`);
272
274
  // Detect team creation from TeamCreate tool_result
273
275
  if (entry.pendingTeamCreate && entry.pendingTeamCreate === ev.toolUseId) {
274
276
  const { extractTeamName, startTeamInboxWatcher } = await import("./team-inbox-watcher.ts");
275
277
  const teamName = extractTeamName(ev.output ?? "");
278
+ console.log(`[chat] session=${sessionId} TeamCreate result matched, extracted teamName=${teamName}`);
276
279
  if (teamName && !entry.teamNames.has(teamName)) {
277
280
  entry.teamNames.add(teamName);
278
281
  const watcher = startTeamInboxWatcher(teamName, {
@@ -168,14 +168,30 @@ function inferMemberStatus(messages: unknown[], agentName: string): string {
168
168
  return "active";
169
169
  }
170
170
 
171
- /** Extract team name from TeamCreate tool_result output */
171
+ /** Extract team name from TeamCreate tool_result output.
172
+ * Output may be plain JSON, or a content-block array like:
173
+ * [{"type":"text","text":"{ \"team_name\": \"foo\" }"}] */
172
174
  export function extractTeamName(output: string): string | null {
173
175
  try {
174
176
  const parsed = JSON.parse(output);
175
- return parsed?.team_name ?? parsed?.name ?? null;
176
- } catch {
177
- // Try regex: look for team_name in text
178
- const match = output.match(/"team_name"\s*:\s*"([^"]+)"/);
179
- return match?.[1] ?? null;
180
- }
177
+ // Direct JSON object: { team_name: "foo" }
178
+ if (parsed && !Array.isArray(parsed)) {
179
+ return parsed.team_name ?? parsed.name ?? null;
180
+ }
181
+ // Content-block array: [{"type":"text","text":"..."}]
182
+ if (Array.isArray(parsed)) {
183
+ for (const block of parsed) {
184
+ if (block?.type === "text" && typeof block.text === "string") {
185
+ try {
186
+ const inner = JSON.parse(block.text);
187
+ if (inner?.team_name) return inner.team_name;
188
+ if (inner?.name) return inner.name;
189
+ } catch { /* not JSON, try next block */ }
190
+ }
191
+ }
192
+ }
193
+ } catch { /* not valid JSON at all */ }
194
+ // Fallback regex
195
+ const match = output.match(/"team_name"\s*:\s*"([^"]+)"/);
196
+ return match?.[1] ?? null;
181
197
  }