@teammates/cli 0.4.0 → 0.4.1

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/adapter.d.ts CHANGED
@@ -87,6 +87,8 @@ export declare function buildTeammatePrompt(teammate: TeammateConfig, taskPrompt
87
87
  services?: InstalledService[];
88
88
  sessionFile?: string;
89
89
  recallResults?: SearchResult[];
90
+ /** Contents of USER.md — injected just before the task. */
91
+ userProfile?: string;
90
92
  /** Token budget for the prompt wrapper (default 64k). Task is excluded. */
91
93
  tokenBudget?: number;
92
94
  }): string;
package/dist/adapter.js CHANGED
@@ -198,6 +198,10 @@ export function buildTeammatePrompt(teammate, taskPrompt, options) {
198
198
  // ── Current date/time (required, small) ─────────────────────────
199
199
  const now = new Date();
200
200
  parts.push(`**Current date:** ${now.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })} (${today})\n**Current time:** ${now.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" })}\n\n---\n`);
201
+ // ── User profile (always included when present) ────────────────
202
+ if (options?.userProfile?.trim()) {
203
+ parts.push(`## User Profile\n\n${options.userProfile.trim()}\n\n---\n`);
204
+ }
201
205
  // ── Task (always included, excluded from budget) ────────────────
202
206
  parts.push(`## Task\n\n${taskPrompt}\n\n---\n\n**REMINDER: After completing the task and updating session/memory files, you MUST produce a text response starting with \`TO: user\`. An empty response is a bug.**`);
203
207
  return parts.join("\n");
@@ -3,6 +3,7 @@ import { buildTeammatePrompt, formatHandoffContext } from "./adapter.js";
3
3
  function makeConfig(overrides) {
4
4
  return {
5
5
  name: "beacon",
6
+ type: "ai",
6
7
  role: "Platform engineer.",
7
8
  soul: "# Beacon\n\nBeacon owns the recall package.",
8
9
  wisdom: "",
@@ -149,11 +149,22 @@ export class CliProxyAdapter {
149
149
  const recall = teammatesDir
150
150
  ? await queryRecallContext(teammatesDir, teammate.name, prompt)
151
151
  : undefined;
152
+ // Read USER.md for injection into the prompt
153
+ let userProfile;
154
+ if (teammatesDir) {
155
+ try {
156
+ userProfile = await readFile(join(teammatesDir, "USER.md"), "utf-8");
157
+ }
158
+ catch {
159
+ // USER.md may not exist yet — that's fine
160
+ }
161
+ }
152
162
  fullPrompt = buildTeammatePrompt(teammate, prompt, {
153
163
  roster: this.roster,
154
164
  services: this.services,
155
165
  sessionFile,
156
166
  recallResults: recall?.results,
167
+ userProfile,
157
168
  });
158
169
  }
159
170
  else {
@@ -219,6 +230,7 @@ export class CliProxyAdapter {
219
230
  const command = this.options.commandPath ?? this.preset.command;
220
231
  const args = this.preset.buildArgs({ promptFile, prompt }, {
221
232
  name: "_router",
233
+ type: "ai",
222
234
  role: "",
223
235
  soul: "",
224
236
  wisdom: "",
@@ -69,11 +69,22 @@ export class CopilotAdapter {
69
69
  const recall = teammatesDir
70
70
  ? await queryRecallContext(teammatesDir, teammate.name, prompt)
71
71
  : undefined;
72
+ // Read USER.md for injection into the prompt
73
+ let userProfile;
74
+ if (teammatesDir) {
75
+ try {
76
+ userProfile = await readFile(join(teammatesDir, "USER.md"), "utf-8");
77
+ }
78
+ catch {
79
+ // USER.md may not exist yet — that's fine
80
+ }
81
+ }
72
82
  fullPrompt = buildTeammatePrompt(teammate, prompt, {
73
83
  roster: this.roster,
74
84
  services: this.services,
75
85
  sessionFile,
76
86
  recallResults: recall?.results,
87
+ userProfile,
77
88
  });
78
89
  }
79
90
  else {
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import { EchoAdapter } from "./echo.js";
3
3
  const teammate = {
4
4
  name: "beacon",
5
+ type: "ai",
5
6
  role: "Platform engineer.",
6
7
  soul: "# Beacon\n\nBeacon owns the recall package.",
7
8
  wisdom: "",
package/dist/banner.d.ts CHANGED
@@ -2,18 +2,21 @@
2
2
  * Animated startup banner for @teammates/cli.
3
3
  */
4
4
  import { type Constraint, Control, type DrawingContext, type Rect, type Size } from "@teammates/consolonia";
5
+ import type { PresenceState } from "./types.js";
5
6
  export type ServiceStatus = "bundled" | "missing" | "not-configured" | "configured";
6
7
  export interface ServiceInfo {
7
8
  name: string;
8
9
  status: ServiceStatus;
9
10
  }
10
11
  export interface BannerInfo {
11
- adapterName: string;
12
+ /** Display name shown in the banner (user alias or adapter name). */
13
+ displayName: string;
12
14
  teammateCount: number;
13
15
  cwd: string;
14
16
  teammates: {
15
17
  name: string;
16
18
  role: string;
19
+ presence: PresenceState;
17
20
  }[];
18
21
  services: ServiceInfo[];
19
22
  }
@@ -66,6 +69,8 @@ export declare class AnimatedBanner extends Control {
66
69
  * If the animation already reached the hold point, it resumes immediately.
67
70
  */
68
71
  releaseHold(): void;
72
+ /** Update service statuses and rebuild the banner lines. */
73
+ updateServices(services: ServiceInfo[]): void;
69
74
  /** Cancel any pending animation timer. */
70
75
  dispose(): void;
71
76
  measure(constraint: Constraint): Size;
package/dist/banner.js CHANGED
@@ -72,7 +72,7 @@ export class AnimatedBanner extends Control {
72
72
  const gap = " ";
73
73
  const lines = [];
74
74
  // TM logo row 1 + adapter info
75
- lines.push(concat(tp.accent(tmTop), tp.text(gap + info.adapterName), tp.muted(` · ${info.teammateCount} teammate${info.teammateCount === 1 ? "" : "s"}`), tp.muted(` · v${PKG_VERSION}`)));
75
+ lines.push(concat(tp.accent(tmTop), tp.text(gap + info.displayName), tp.muted(` · ${info.teammateCount} teammate${info.teammateCount === 1 ? "" : "s"}`), tp.muted(` · v${PKG_VERSION}`)));
76
76
  // TM logo row 2 + cwd
77
77
  lines.push(concat(tp.accent(tmBot), tp.muted(gap + info.cwd)));
78
78
  // Service status rows
@@ -92,9 +92,14 @@ export class AnimatedBanner extends Control {
92
92
  // blank
93
93
  lines.push("");
94
94
  this._rosterStart = lines.length;
95
- // Teammate roster
95
+ // Teammate roster (with presence indicators)
96
96
  for (const t of info.teammates) {
97
- lines.push(concat(tp.accent(" ● "), tp.accent(`@${t.name}`.padEnd(14)), tp.muted(t.role)));
97
+ const presenceDot = t.presence === "online"
98
+ ? tp.success(" ● ")
99
+ : t.presence === "reachable"
100
+ ? tp.warning(" ● ")
101
+ : tp.error(" ● ");
102
+ lines.push(concat(presenceDot, tp.accent(`@${t.name}`.padEnd(14)), tp.muted(t.role)));
98
103
  }
99
104
  // blank
100
105
  lines.push("");
@@ -261,6 +266,16 @@ export class AnimatedBanner extends Control {
261
266
  this._schedule(80);
262
267
  }
263
268
  }
269
+ /** Update service statuses and rebuild the banner lines. */
270
+ updateServices(services) {
271
+ this._info.services = services;
272
+ this._buildFinalLines();
273
+ // If animation is done, refresh immediately
274
+ if (this._phase === "done") {
275
+ this._lines = this._finalLines;
276
+ this._apply();
277
+ }
278
+ }
264
279
  /** Cancel any pending animation timer. */
265
280
  dispose() {
266
281
  if (this._timer) {
package/dist/cli-args.js CHANGED
@@ -102,7 +102,6 @@ ${chalk.bold("@teammates/cli")} — Agent-agnostic teammate orchestrator
102
102
 
103
103
  ${chalk.bold("Usage:")}
104
104
  teammates <agent> Launch session with an agent
105
- teammates claude Use Claude Code
106
105
  teammates codex Use OpenAI Codex
107
106
  teammates aider Use Aider
108
107