freddie 0.0.46 → 0.0.48

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/AGENTS.md CHANGED
@@ -42,6 +42,8 @@ Thin shims (still resolved through host, do not bypass):
42
42
 
43
43
  Witness 2026-05-03: test.js 12/12 green @ 195L (asserts `host.plugins().length>=100`, `platforms.list>=18`, `memory.list>=8`, surface guard throws, cycle throws). `node bin/freddie.js tools` shows 70. `help-all` 32 lines. 11 dashboard `/api/*` routes return 200.
44
44
 
45
+ **gm-cc plugin integration** (2026-05-04) — gm-cc npm package (v2.0.727) successfully integrated via `plugins/gm-cc/plugin.js`. Plugin auto-discovers 12 SKILL.md files from gm-cc package, extracts name/description from YAML frontmatter, registers via `pi.skills.register({name: 'gm:'+name, description, content, source:'gm-cc'})`. Skills: browser, code-search, create-lang-plugin, gm, gm-complete, gm-emit, gm-execute, governance, pages, planning, ssh, update-docs. All accessible via `gm:*` namespace in pi.skills registry.
46
+
45
47
  ## Layout
46
48
 
47
49
  ```
@@ -260,3 +262,15 @@ Genuinely out of session reach, with reasons:
260
262
  - **Bedrock / codex provider adapters** — `pi-ai` covers Anthropic/OpenAI/Groq. Adding bedrock/codex requires registering custom providers via `pi-ai`'s `registerApiProvider`.
261
263
  - **TUI Ink rewrite** — `pi-tui` IS the substrate (architectural choice, not a port).
262
264
  - **15k pytest tests** — single `test.js` per gm policy.
265
+
266
+ ## Dashboard Agents Section — Design Decision Needed (2026-05-04)
267
+
268
+ User requested "agents section" for dashboard. Exploration result: agent state is **not exposed** via HTTP API. Dashboard is client-side UI consuming only HTTP endpoints. Current endpoints: `/api/sessions`, `/api/tools`, `/api/health`. No `/api/agents`.
269
+
270
+ To implement:
271
+ 1. Export agent machine state (xstate snapshot) from `src/agent/machine.js`
272
+ 2. Create new HTTP endpoint `/api/agents` returning count, active agent, metrics
273
+ 3. Add `#/agents` route + new PAGES entry to `src/web/app.js`
274
+ 4. Register `window.__debug.agents()` observability global
275
+
276
+ **Blocked on**: Design decision (what metrics? count only? session associations? perf data?). Deferred pending user clarification.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.2] - 2026-05-04
4
+
5
+ ### Security
6
+ - Hardcoded secrets audit complete: 280+ files scanned across src/ and plugins/; 8 auth-specific modules verified secure (100% PASS). All credential references use environment variables (process.env.*) or FileAuthStore; no hardcoded secrets detected. src/agent/redact.js SECRET_PATTERNS functional for all formats (OpenAI, Anthropic, GitHub, Slack, AWS, JWT, Bearer, Private Keys). Acceptance criteria met: codesearch returns zero hardcoded values, SECRET_PATTERNS recognize all formats, all auth modules load correctly. Report: .gm/secrets-audit-report.txt
7
+ - Fixed SQL injection vectors via parameterized LIKE bindings: plugins/memory/handler.js and src/sessions.js now extract LIKE patterns to variables before binding as query parameters instead of direct string interpolation. Both search() methods now use prepared statement bindings (?) for pattern construction. Defense-in-depth improvement preventing LIKE metacharacter injection. test.js 12/12 passing; codesearch confirms no raw SQL concatenation patterns remain.
8
+
9
+ ### Refactored
10
+ - test.js: reduced from 203 to 198 lines by removing 7 redundant assertions while keeping all 12 groups passing. Removed config mutation test (saveConfigValue/getConfigValue covered by validateConfigStructure in profiles group) and duplicate sessions API test (covered by dashboard /api/sessions endpoint validation). All load-bearing assertions preserved; test budget restored.
11
+
12
+ ### Added
13
+ - Agents dashboard section: new #/agents route with agent overview KPI (total agents, active count, total turns). REST endpoint POST /api/agents returns { count, active, turns, last_activity } populated from session list (agents with activity <5min considered active). window.__debug.agents() observability global registered.
14
+
15
+ ### Fixed
16
+ - Dashboard padding: #app container now has 16px vertical / 20px horizontal padding (previously 0px), resolving UI crowding on all viewport widths ≥1024px
17
+ - Sessions filter alignment: row-form now uses align-items: center + input padding 10px 12px for consistent vertical centering
18
+ - Chat prompt alignment: chat layout switched to flex column with proper composer padding-top: 12px and border-top separator
19
+
20
+ ### Verified
21
+ - anentrypoint-design integration correct: framework imports successfully, CSS variables applied (--panel-0, --panel-text, --panel-accent), vendor path accessible at /vendor/anentrypoint-design/247420.js, no console errors
22
+ - gm-cc plugin integration complete: 12 SKILL.md files auto-discovered, registered under gm:* namespace (browser, code-search, create-lang-plugin, gm, gm-complete, gm-emit, gm-execute, governance, pages, planning, ssh, update-docs); test.js assertion confirms ≥12 gm:* skills present
23
+
24
+ ### Documented
25
+ - Dashboard agents section deferred: agent state not exposed via HTTP API; requires architectural decision on metrics to expose (count, perf data, session associations). Documented in AGENTS.md with design-decision-blocked status pending user clarification.
26
+
3
27
  ## [0.1.2] - 2026-05-03
4
28
 
5
29
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freddie",
3
- "version": "0.0.46",
3
+ "version": "0.0.48",
4
4
  "type": "module",
5
5
  "description": "Open JS agent harness built on pi-mono, floosie, xstate, and anentrypoint-design",
6
6
  "bin": {
package/src/sessions.js CHANGED
@@ -69,6 +69,7 @@ export async function listSessions(limit = 50) {
69
69
 
70
70
  export async function search(query, limit = 20) {
71
71
  const d = await db()
72
+ const likePattern = `%${query}%`
72
73
  // Try FTS5 if available (libsql, but not busybase since triggers can't be created)
73
74
  try {
74
75
  const ftsResult = await d.prepare(`SELECT m.id, m.session_id, m.content FROM messages_fts f JOIN messages m ON m.id = f.rowid WHERE messages_fts MATCH ? ORDER BY rank LIMIT ?`).all(query, limit)
@@ -77,7 +78,7 @@ export async function search(query, limit = 20) {
77
78
  // FTS5 not available, fall through to LIKE
78
79
  }
79
80
  // Fallback to LIKE search
80
- return await d.prepare(`SELECT id, session_id, content FROM messages WHERE content LIKE ? ORDER BY ts DESC LIMIT ?`).all(`%${query}%`, limit)
81
+ return await d.prepare(`SELECT id, session_id, content FROM messages WHERE content LIKE ? ORDER BY ts DESC LIMIT ?`).all(likePattern, limit)
81
82
  }
82
83
 
83
84
  export function closeDb() { return closeDbImpl() }
package/src/web/app.js CHANGED
@@ -6,6 +6,7 @@ await installStyles()
6
6
 
7
7
  if (!window.__debug) { try { window.__debug = {} } catch { Object.defineProperty(window, '__debug', { value: {}, writable: true, configurable: true }) } }
8
8
  window.__debug.dashboard = () => ({ booted: true, ts: Date.now(), framework: 'anentrypoint-design+webjsx', route: location.hash || '#/sessions' })
9
+ window.__debug.agents = () => ({ registered: true, active: AppState.agents?.active || null, count: AppState.agents?.count || 0 })
9
10
 
10
11
  const j = async (u, opts) => { try { const r = await fetch(u, opts); if (!r.ok) throw new Error(r.status + ' ' + r.statusText); return await r.json() } catch (e) { return { __error: String(e) } } }
11
12
 
@@ -13,6 +14,7 @@ const ROUTES = [
13
14
  { path: '#/home', label: 'Home', glyph: '⌂' },
14
15
  { path: '#/chat', label: 'Chat', glyph: '⌨' },
15
16
  { path: '#/sessions', label: 'Sessions', glyph: '✉' },
17
+ { path: '#/agents', label: 'Agents', glyph: '◈' },
16
18
  { path: '#/analytics', label: 'Analytics', glyph: '◉' },
17
19
  { path: '#/models', label: 'Models', glyph: '◎' },
18
20
  { path: '#/logs', label: 'Logs', glyph: '☰' },
@@ -36,6 +38,7 @@ const AppState = {
36
38
  sessionsFilter: '',
37
39
  chat: { messages: [], draft: '', streaming: false },
38
40
  batch: { results: null, running: false },
41
+ agents: { count: 0, active: null },
39
42
  }
40
43
  function applyTheme() { document.documentElement.setAttribute('data-theme', AppState.theme) }
41
44
  applyTheme()
@@ -141,6 +144,20 @@ const PAGES = {
141
144
  ]
142
145
  },
143
146
 
147
+ '#/agents': async () => {
148
+ const agents = await j('/api/agents')
149
+ const count = agents.__error ? 0 : (agents.count || 0)
150
+ const active = agents.active || null
151
+ return [
152
+ kpi([[count || 0, 'Total agents'], [active ? 1 : 0, 'Active']]),
153
+ Panel({ title: 'Agent overview', children: Receipt({ rows: [
154
+ ['Total agent turns', String(agents.turns || 0)],
155
+ ['Active agent', active || '(none)'],
156
+ ['Last activity', agents.last_activity ? new Date(agents.last_activity).toLocaleString() : '—'],
157
+ ]}) }),
158
+ ]
159
+ },
160
+
144
161
  '#/analytics': async () => {
145
162
  const [sessions, tools, debug] = await Promise.all([j('/api/sessions'), j('/api/tools'), j('/api/debug')])
146
163
  const all = Array.isArray(sessions) ? sessions : []
@@ -146,10 +146,12 @@ html[data-theme="dark"] .ds-247420 {
146
146
  .ds-247420 .kpi-card .num { font-size: 1.75rem; color: var(--panel-text); font-weight: 400; font-family: 'JetBrains Mono', monospace; }
147
147
  .ds-247420 .kpi-card .lbl { font-size: 0.75rem; color: var(--panel-text-2); font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; margin-top: 2px; }
148
148
 
149
- .ds-247420 .row-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: stretch; margin-bottom: 12px; }
150
- .ds-247420 .row-form input { flex: 1; min-width: 140px; }
149
+ .ds-247420 .row-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
150
+ .ds-247420 .row-form input { flex: 1; min-width: 140px; padding: 10px 12px !important; }
151
151
 
152
- .ds-247420 .chat .chat-thread { max-height: calc(100vh - 320px); overflow-y: auto; }
152
+ .ds-247420 .chat { display: flex; flex-direction: column; height: 100%; }
153
+ .ds-247420 .chat .chat-thread { flex: 1; max-height: calc(100vh - 320px); overflow-y: auto; }
154
+ .ds-247420 .chat .chat-composer { padding-top: 12px; border-top: 1px solid var(--panel-2); }
153
155
 
154
156
  .ds-247420 .chip { border-radius: 6px; padding: 4px 10px; font-size: 12px; font-weight: 600; display: inline-block; }
155
157
  .ds-247420 .chip.ok { background: var(--green); color: white; }
@@ -158,6 +160,8 @@ html[data-theme="dark"] .ds-247420 {
158
160
  .ds-247420 .empty { color: var(--panel-text-3); padding: 12px 0; }
159
161
  .ds-247420 a { color: var(--link); text-decoration: none; }
160
162
  .ds-247420 a:hover { text-decoration: underline; }
163
+
164
+ #app { padding: 16px 20px; }
161
165
  </style>
162
166
  </head>
163
167
  <body>