Raw JSON report machine-readable
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 1042,
"has_wiki": true,
"homepage": null,
"languages": {
"TypeScript": 917283
},
"pushed_at": "2026-07-23T02:06:16Z",
"created_at": "2026-05-26T13:57:21Z",
"owner_type": "User",
"updated_at": "2026-07-23T02:06:21Z",
"description": null,
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "TypeScript",
"significant_languages": [
"TypeScript"
]
},
"owner": {
"blog": null,
"name": "Alexander Paramonov",
"type": "User",
"login": "AlexParamonov",
"company": null,
"location": null,
"followers": 19,
"avatar_url": "https://avatars.githubusercontent.com/u/352030?v=4",
"created_at": "2010-08-02T19:32:15Z",
"is_verified": null,
"public_repos": 58,
"account_age_days": 5833
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [],
"recent_commits": [
{
"oid": "5057ae195a4928628428c1ab1196c05f9a837b99",
"body": null,
"is_bot": false,
"headline": "Merge branch 'issue/package-name-extension-matching'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T01:49:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fd73949a8b42efe36d2420e145d74633b77af514",
"body": "…gent-runner\n\nThe cache guard `if (cached !== undefined) return cached` defeated\nnegative caching: storing undefined for not-found paths was an inert\ndead store, since a subsequent .get returns undefined either way and\nthe guard falls through to recompute. Caching the negative result\nhonors the issue's 'one readFileSync per extension path, cached'\nconstraint for the common no-package.json case across subagent runs.\n\nBehavior preserved: same return values; tests + typecheck green.",
"is_bot": false,
"headline": "refactor: cache negative package-name lookups via presence check in a…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T01:47:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2c3b52828b26598330ca960fae64b73eb49b8d2d",
"body": "…runner\n\nextensionPackageName interleaved cache writes with the directory climb:\npackageNameCache.set(extPath, X); return X; appeared 4 times. Split into\na memoizing wrapper + resolvePackageShortName, the pure nearest-ancestor\nclimb. Dedupes the cache writes to one site and leaves the resolver's\ncontrol flow free of caching noise. Behavior unchanged: cache miss\ncomputes then stores, hit returns cached.",
"is_bot": false,
"headline": "refactor: separate memoization from package-name resolution in agent-…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T01:35:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "54b57f9b6d3742373242a921646196e00ee74fa3",
"body": "…losures",
"is_bot": false,
"headline": "refactor: extract filterOverride to deduplicate whitelist/blacklist c…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T01:28:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "97a0d14604cdf3758a01ce928f07a6ec84ee2fea",
"body": null,
"is_bot": false,
"headline": "refactor: drop `` ?? \"\" `` sentinel in filterExtensions match expression",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T01:27:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1c1dd7605735eb220543375e2bce940030a1dc06",
"body": "- Add test for package-name matching when extension is installed\n inside node_modules (review feedback: untested boundary case)\n- Extract shared filter logic into filterExtensions() helper,\n eliminating duplication between whitelist and blacklist branches\n- Fix subtle bug: || operator returns first truthy operand (not\n boolean); coerce with !! to ensure correct comparison with invert\n flag",
"is_bot": false,
"headline": "test(agents): add node_modules path coverage; refactor extension filter",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T01:18:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b2b4f1ddcaa6719e1ba8a09a418bfc9b97cfb135",
"body": "- Fix cache bug: store undefined instead of empty string for not-found\n entries (consistent return value across cache hits and misses)\n- Export buildExtOverride for direct unit testing (eliminates runAgent\n indirection in tests)\n- Export resetPackageNameCache for test isolation\n- Rewrite package-n\n[…]\natching tests to use buildExtOverride directly\n (removes ~300 lines of duplicated mock setup)\n- Add malformed package.json test (graceful degradation coverage)\n- Add cache consistency and reset tests",
"is_bot": false,
"headline": "fix: address code review for package-name extension matching",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T00:57:24Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1be86f9c151219061b75572e933d05d517ca0e48",
"body": "- Use resolved path for directory climbing in extensionPackageName\n (latent bug: relative paths would walk from wrong base)\n- Fix createPkgDir test helper for root-level entries (no subdirectory)\n- Add test for package root entry matching\n- Update issue to clarify case-insensitive matching is new behavior",
"is_bot": false,
"headline": "fix: address code review feedback",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T00:43:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0a14be5e3c707507cb214a00caca5d3a6af03915",
"body": "When matching extension names in extensions/exclude_extensions frontmatter,\nalso match against the package's unscoped short name read from package.json.\nThis makes extensions: [\"pi-subagents\"] work for a package installed as\n@scope/pi-subagents, instead of only matching the directory-derived name.\n\n\n[…]\ntensions declares the entry\n- Case-insensitive matching for both path-derived and package names\n- Warnings when requested extension names don't match any loaded extension\n\nPort from pi-subagents #143.",
"is_bot": false,
"headline": "feat: match extensions by package name from package.json",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-23T00:32:39Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "13fe7c78cdf5231eb86b44c2209de89425518f85",
"body": null,
"is_bot": false,
"headline": "Bump version",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T19:55:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7923e61e96da2e23a41475da5b457acab0fa9880",
"body": "Import ThinkingLevel from @earendil-works/pi-ai instead of maintaining\na local union literal. Picks up max (and future levels) automatically.\n\nCloses #8",
"is_bot": false,
"headline": "Merge branch 'issue/import-thinking-level-from-pi-ai'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T13:46:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b42ebb0e72ce34215fa18c25202ec2cb63e4ed80",
"body": "…ing: max\n\n- Remove VALID_THINKING_LEVELS and parseThinkingLevel tests from\n utils.test.ts — they test a one-liner array lookup, not behavior\n- Add behavior test in agent-types-discovery.test.ts: frontmatter\n with thinking: max produces a valid agent config with thinkingLevel: max",
"is_bot": false,
"headline": "test: remove implementation-detail tests, add behavior test for think…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T13:32:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "15ba6b0da1268463845e97b1cf14480b68733633",
"body": "…evels\n\nThe old tests checked array contents and exact counts — implementation\ndetails that break when new levels are added. Replace with tests that\nverify actual behavior:\n\n- parseThinkingLevel accepts max (the behavioral change this PR introduces)\n- parseThinkingLevel rejects invalid/unknown strings\n- parseThinkingLevel handles undefined input gracefully\n- parseThinkingLevel accepts all known standard levels (single test)\n- VALID_THINKING_LEVELS is non-empty and contains UI-required levels",
"is_bot": false,
"headline": "test: replace implementation tests with behavior tests for thinking l…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T13:30:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "604341a9132422a4fa0c7e3e7a9d15492a19b868",
"body": "Replace hand-maintained ThinkingLevel union with ModelThinkingLevel\nimported from @earendil-works/pi-ai. This picks up new levels\n(eg max) automatically without manual sync.\n\n- src/types.ts: import ModelThinkingLevel, alias as ThinkingLevel\n- src/utils.ts: add 'max' to VALID_THINKING_LEVELS\n- test/utils.test.ts: add tests for VALID_THINKING_LEVELS and\n parseThinkingLevel covering all levels including max",
"is_bot": false,
"headline": "refactor: import ThinkingLevel from @earendil-works/pi-ai",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T13:16:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "33ed3d613341b72b68d169760b49654dae29c917",
"body": null,
"is_bot": false,
"headline": "chore: bump version to 1.4.9",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T12:53:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "990e0116f85b8378d3f96257243ff9e4790a5f21",
"body": "pi 0.80.8 replaced CreateAgentSessionOptions.modelRegistry with\nmodelRuntime. The old option is silently ignored at runtime and\ncauses a type error against 0.80.8+ types.\n\ncreateAgentSession now creates its own ModelRuntime from auth.json\nand models.json. Extensions load in the subagent session and\nregister their providers before the first API call, so custom\nproviders continue to work.",
"is_bot": false,
"headline": "fix: remove deprecated modelRegistry from createAgentSession",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-17T12:52:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1981c803a2f4c135fabb4a40a692e50d5cd2513a",
"body": null,
"is_bot": false,
"headline": "Version bump",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-11T16:51:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2cdee4d476312647058d03323328fb5418566d00",
"body": null,
"is_bot": false,
"headline": "Merge branch 'issue/background-agent-cleanup-fix'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-09T00:18:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a1a910bb7ce246f31c86e746f1155f7f744f6106",
"body": "cleanup() evicted any terminal record older than 10 minutes regardless of\nwhether the LLM had read the result. A background agent that completed before\nits nudge fired (LLM busy, session switched mid-execution) could be wiped\nbefore the result was delivered, the same result-loss bug class v0.10.4\nad\n[…]\nhe result, and when a background nudge successfully delivers\nthe full result to the LLM. A failed nudge delivery leaves the record\nunconsumed so cleanup keeps it around rather than wiping it silently.",
"is_bot": false,
"headline": "fix: preserve unconsumed agent records in cleanup timer",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-09T00:03:56Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9d4c1ccf3eb41bf19a6387aaf912c0b575e1b90b",
"body": "- Group terms under subheadings (Core concepts, Configuration, Worktrees, Runtime)\n- Tighten definitions: remove implementation details, keep what-is\n- Remove Example dialogue and Flagged ambiguities sections (not glossary material)",
"is_bot": false,
"headline": "Migrate CONTEXT.md to grill skill format",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-08T23:40:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a660f90210cf495a18d934d1ee3e5f550dd6fc49",
"body": null,
"is_bot": false,
"headline": "Cleanup",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-08T23:33:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f7616e4dc3baf9a9249a278b95ff0cda93e6a4c3",
"body": null,
"is_bot": false,
"headline": "chore: bump version to 1.4.7",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T23:40:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "12d4f7c76df833ed174c2296ef80c0ae753e30a1",
"body": "Both callers built (record.result ?? \"\") + getStatusNote(record.lifecycle)\ninline. The previous commit (3025e8a) had to re-sync these two after they\ndiverged on separator handling. Hoist to a shared helper next to\nbuildAgentDetails (same two callers, same record->display shape) so the\nnullish default and separator ownership live in one place.",
"is_bot": false,
"headline": "refactor: extract formatResultContent shared by nudge and tool result",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T23:37:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3025e8ac454b25ca1d59f3cfb8fdb594fd94a0b6",
"body": "spawn-coordinator interpolated ${record.result ?? \"\"} ${getStatusNote()}\nwith a literal space between operand and getStatusNote(), but\ngetStatusNote() already owns the leading separator (its output starts\nwith \" (\" for a note). The extra space produced a double space when a\nnote existed and a trailing space when none did. tool-execution already\nused the clean \"+ statusNote\" form; normalize spawn-coordinator to\nmatch so both callers delegate the separator to getStatusNote.",
"is_bot": false,
"headline": "refactor: drop redundant separator in subagent-result content",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T23:27:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a5fb34cc83b6e4007eaa2a77083aa0621f3044fb",
"body": "NOTES unioned real AgentStatus keys with synthetic tokens\n'stoppedByUser'/'stoppedByAgent' and modeled stop messages as Partial\neven though both StopInitiator values have one. Split into\nSTATUS_NOTES (Partial<Record<AgentStatus,string>>) and an exhaustive\nSTOP_NOTES (Record<StopInitiator,string>), and flatten the 3-level\nnested ternary via 'stoppedBy ?? \"agent\"'. Behavior unchanged.",
"is_bot": false,
"headline": "refactor: separate stop-initiator notes from status notes in status-note",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T23:17:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "169f1a0f03ef6af12cd55a6ccf105fc7b138912b",
"body": "test/status-note.test.ts passed status: \"foo\" to getStatusNote, which is\nnot a valid AgentStatus after the NOTES type tightening in 862b4b5. It\nonly escaped because tsconfig excludes test/. Use status: \"completed\"\n(a noteless but valid status) and rename the case to match what it\nactually tests. Behaviour unchanged.",
"is_bot": false,
"headline": "refactor: use valid AgentStatus in status-note test",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T23:08:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "862b4b52c3d840e9c75f6e57249aa3f4864789e0",
"body": "Record<string,string> claimed NOTES[lifecycle.status] always returned a\nstring, when it is undefined for queued/running/completed/error. The\ntruthy 'note ? ... : \"\"' check existed only because of that. Use\nPartial<Record<AgentStatus | stoppedBy-variants, string>> so the value\ntype is honestly string | undefined and property-access typos are caught\nat compile time. Behavior unchanged.",
"is_bot": false,
"headline": "refactor: tighten NOTES record type in status-note",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T23:00:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "07db848416248bd510a17d041807cd1075828697",
"body": "The \"user\" | \"agent\" literal union was duplicated across\nAgentLifecycle.stoppedBy and the abort/stopAgent signatures. Give it\nan exported name so the concept has one source of truth and is named\nexplicitly rather than described only in prose.",
"is_bot": false,
"headline": "refactor: extract StopInitiator type for stop origin",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T22:54:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "626268d760b595f84dd5f742c5c600d378633f63",
"body": "Compute the status note directly via property access instead of\nbuilding a synthetic noteKey (mixed real statuses + 'stoppedByUser'/\n'stoppedByAgent' strings) and indexing NOTES with it. Removes the\n'let' mutation and the 'as string' cast that existed only to let\nnon-status strings share a variable with AgentStatus.",
"is_bot": false,
"headline": "refactor: flatten getStatusNote note lookup in status-note",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T22:47:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1e75d1a5bba7f0359ad3a122bdedfb9dcd8a40a0",
"body": "When the agent uses StopAgent to kill a stuck subagent, the nudge\nsaid 'STOPPED BY THE USER' causing the agent to think the human\nintervened and retry unnecessarily.\n\n- Add stoppedBy field to AgentLifecycle ('user' | 'agent')\n- UI menu passes 'user', StopAgent tool passes 'agent'\n- Status note: 'STOPPED BY THE USER' for user stops,\n 'stopped before completion' for agent stops\n- Include short agent ID in nudge header so the agent can\n match the nudge to the specific subagent it stopped",
"is_bot": false,
"headline": "Distinguish user vs agent stops in StopAgent",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-07T22:33:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c7a80572dd53b01bbbaf952056ece435535ebc23",
"body": null,
"is_bot": false,
"headline": "chore: bump version to 1.4.6",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-07-01T21:27:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bf620bf6b96814ad6d2d3f42145cd154639f93ee",
"body": null,
"is_bot": false,
"headline": "Add delta input tests",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T23:37:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "01866e31edc5c2bad3f2b5e1131c1aae475750b4",
"body": "The setter no longer routes through setAgentVisibility and it isn't a\nwidget stats-visibility flag, so it doesn't belong in that union.",
"is_bot": false,
"headline": "refactor: remove deltaInputTokens from setAgentVisibility union",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T23:36:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "81c197334246fc70c32d8647a7b1d4e2696ccc6e",
"body": "cacheRead was extracted in agent-runner, smuggled through an\nonAssistantUsage callback typed LifetimeUsage (which omits it),\nthen recovered by cast in agent-manager. Introduce AgentUsage type,\ntype the callback with it, and drop the cast and the dead\nUsageWithCacheRead alias.",
"is_bot": false,
"headline": "refactor: make cacheRead first-class via AgentUsage in usage tracking",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T23:35:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6194481af2a8aa05c760a1675b54181cc1fec0b4",
"body": "Users explicitly enable this for vLLM. Default OFF avoids incorrect\ncounts for cloud providers that legitimately have cacheRead=0.",
"is_bot": false,
"headline": "config: change deltaInputTokens default to false (opt-in)",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T23:11:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1dbdc64a93be4f69795fcc9e727eebdb28f4ab18",
"body": "Adds a toggle in Widget Settings > Usage Stats to enable/disable\nthe input token delta estimation for vLLM (which doesn't report\ncache hits). Default: ON.",
"is_bot": false,
"headline": "widget: add deltaInputTokens toggle setting",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T23:02:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0bfa330a02733ac7957e4cb5e3d3f98b4e92d53f",
"body": "vLLM doesn't report prompt_tokens_details.cached_tokens, so usage.input\nis always the full prompt_tokens. Estimate new tokens as delta from\nprevious message's input when cacheRead is 0.\n\nCloud models with cacheRead still show actual input tokens.",
"is_bot": false,
"headline": "usage: show input token delta for vLLM (no cache reporting)",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T22:58:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7338f186008271bc7cecd805ea11d56ca921b86c",
"body": null,
"is_bot": false,
"headline": "Bump version to 1.4.5",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T02:01:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e5828bf36fc43f59758331555e4b0f751f27eddb",
"body": null,
"is_bot": false,
"headline": "Finally fixed nudge delivery",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T02:00:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e85741a267a40334f97d10dd3c95681cd0c4f923",
"body": "Subagent bindCore calls overwrite the shared runtime's sendMessage\nhandler. When the nudge fires, pi.sendMessage routes to a subagent's\nsession instead of the parent's, causing silent delivery failure.\n\nFix: capture ExtensionContext at spawn time and use ctx.ui.notify()\nas fallback when sendMessage fails. Shows a toast notification\ninforming the user that the agent result is available.",
"is_bot": false,
"headline": "fix: fallback to UI notification when nudge delivery fails",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T00:27:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "974f157ce95493765edfe774e68523b2f445ee37",
"body": "Subagent bindCore calls overwrite the shared ExtensionRuntime's\nsendMessage handler. When a background agent completes, pi.sendMessage\nroutes to a subagent's handler instead of the parent session's,\ncausing silent nudge failure.\n\nCapture ExtensionContext at spawn time. When sendMessage fails,\nfall back to ctx.ui.notify() using the captured context, which\nbypasses the corrupted shared runtime.",
"is_bot": false,
"headline": "fix: fallback to UI notification when nudge sendMessage fails",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-25T00:24:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c71604507ba62d61635b337c8736976b25072ac2",
"body": null,
"is_bot": false,
"headline": "bump 1.4.3",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "74e4a5b2f4e5ff1195777ff6570e58389a224648",
"body": null,
"is_bot": false,
"headline": "refactor: remove unused afterEach import in spawn-coordinator test",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e159cfedba215b9853915de3f0ee1ed9ebd73602",
"body": "- scanAndMerge is internal to agent-types.ts, no external consumers\n- warnSpy in stale-pi test was set up and restored but never asserted\n (assertions removed in earlier commit)",
"is_bot": false,
"headline": "refactor: unexport scanAndMerge, remove dead warnSpy from stale-pi test",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ff600f49a1672910183206b5616ba8c74ad983c0",
"body": null,
"is_bot": false,
"headline": "docs: add pi-ai deliverAs lesson to lessons.md",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7e584da9dc7e8c39834d75d908d27168b5aa26b6",
"body": "- Check parent session state via ctx.isIdle()\n- Use followUp when idle (waits for agent to finish)\n- Use steer when running (queues during current turn)\n- Fixes nudges not rendering after getPiInstance() refactor",
"is_bot": false,
"headline": "fix: use correct deliverAs mode for nudge messages",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "edd9d1fdc08f3b9d118eac9d55e30acd69312404",
"body": null,
"is_bot": false,
"headline": "refactor: extract findActiveConfig helper in agent-types",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f1027fbecc42bcd79f2924bcabcab23dfe5e2a48",
"body": "…estamp per block",
"is_bot": false,
"headline": "fix: remove newline flush trigger for thinking buffer, use single tim…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c0f0e998b1bcd7cd9f9e12add06b0e92fc6f3415",
"body": "…estamps",
"is_bot": false,
"headline": "revert: restore splitAndPrefix for thinking content with per-line tim…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5dbdbddc5fc597edbc6f4db1feae316c45224a92",
"body": "- Replace splitAndPrefix with inline template for thinking paths\n (thinking is a continuous buffer, single timestamp per flush is sufficient)\n- Remove newline-triggered flush, only buffer size triggers flush now\n- Flatten redundant nested conditional in thinking_delta handler\n- Update test docstring and assertions to match new behavior",
"is_bot": false,
"headline": "refactor: simplify thinking buffer flush in output-file",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fa704b76e37d33c1b78fbabe3efad71a13290e66",
"body": null,
"is_bot": false,
"headline": "docs: refactor-7 report",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "84a590ebb7efc2b6eefdfc9da1a511cf9775111d",
"body": "- tool-execution.ts: replace AgentDetailsOptions interface with inline\n type annotation on buildAgentDetails (2 booleans, single use site)\n- agent-discovery.ts: remove unused _filename parameter from parseAgentFile\n and update all call sites",
"is_bot": false,
"headline": "refactor: inline AgentDetailsOptions and remove unused _filename param",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T18:31:37Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2791388a41ceaa04763ed7754b55005970885181",
"body": "SpawnCoordinator captured pi at spawn time and used it for nudges\nfiring later via setTimeout. If the session was disposed between\nspawn and nudge (session replacement, reload, crash, context\noverflow), pi.sendMessage() threw a stale context error.\n\nFix: read pi from shell at nudge time (fresh after reload) and\nswallow stale context errors silently. The nudge simply doesn't\ndeliver when the session is gone, which is correct behavior.",
"is_bot": false,
"headline": "fix: suppress stale ctx error on background agent nudge",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T16:06:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b63344c62c255e5b40c63e623cd5860e6712ad8d",
"body": null,
"is_bot": false,
"headline": "refactor: remove dead CUSTOM_PROMPT_PATH re-export from agent-runner",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:42:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0a62800af42e995185601b61cd69785baae42e7e",
"body": "…NFIG export\n\nloadConfig now merges loaded values over defaults so callers always get\na complete SubagentsConfig. Removes DEFAULT_CONFIG export, DEFAULT_CONFIG\nfallbacks in ConfigStore getter, and local VALID_SYSTEM_PROMPT_MODES\n(moved to config-io.ts). Adds DEFAULT_CONCURRENCY for concurrency resets.",
"is_bot": false,
"headline": "refactor: merge config defaults into loadConfig, eliminate DEFAULT_CO…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:41:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6326971a781973540b45f97da5dc600d0446fb82",
"body": "Comma was removed in the refactor but is needed as a fallback split\npoint when thinking text has no periods. Without it, the entire\nbuffer flushes at once instead of splitting at the nearest pause.",
"is_bot": false,
"headline": "fix: restore comma in sentence boundary detection",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:29:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b7f0607105c02e237f20aa09293c088ea7c84d6d",
"body": "Eliminates 'any' in menu-model-settings, menu-concurrency, and\nmenu-running-agents. Adds Theme import where missing.",
"is_bot": false,
"headline": "refactor: replace remaining 'any' theme types with Theme",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:23:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d560d9545a33f60717aed8642d6ca7023a18249f",
"body": "The IIFE existed only to scope the 'parts' variable. A simple if-block\nwith let achieves the same thing without the indirection.",
"is_bot": false,
"headline": "refactor: replace IIFE with block scope in applyOverflow",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:18:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e8d8cbc661ad28f509b3a44921c883974eb014ef",
"body": "DONE line formatting was duplicated in streamToOutputFile cleanup and\nAgentOutputLog.finalize. Single helper now owns the format string.",
"is_bot": false,
"headline": "refactor: extract formatDoneLine helper in output-file",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:17:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9c67ff0853a545f2d8f5ac204aa673bbc8c08ffe",
"body": "Eliminates duplicated parts-building logic in buildFinishedBlocks and\nbuildRunningBlocks. Both callers construct the same @worktreeLabel / tail -f\ncontinuation; now shared via a single helper.",
"is_bot": false,
"headline": "refactor: extract buildWorktreeOutputParts helper in agent-widget",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:16:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "90928ac5480f847589025264071273041b0b6112",
"body": "- Move CUSTOM_PROMPT_PATH from agent-runner to config-io (belongs with config paths)\n- Move GIT_EXEC_TIMEOUT_MS to utils.ts (shared by agent-runner and worktree-validator)\n- Merge formatTokens and formatTokensCompact into single function with compact flag\n- Move VALID_THINKING_LEVELS to utils.ts (re\n[…]\nt, menu-spawn-wizard\n- Remove unused 'ls' from TOOL_DISPLAY\n- Remove comma from sentence boundary detection (too aggressive for thinking buffer)\n- Update test mock to include CUSTOM_PROMPT_PATH export",
"is_bot": false,
"headline": "refactor: consolidate constants, merge formatTokens, eliminate any types",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-24T15:15:12Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "779e4ddbf5ebd6a98381dfee97263cea78181289",
"body": "- Merge redundant sections (Agent Type Enforcement → Verification, 4 stale task lessons → Config & Refactoring Patterns)\n- Fix createNumericInputSubmenu → createNumericSubmenu (actual function name)\n- Fix section separators: SettingsList supports __sep__ items via SettingsListWrapper\n- Tighten prose throughout",
"is_bot": false,
"headline": "docs: compact lessons.md (108→60 lines, fix 3 inaccuracies)",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-23T23:46:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "efedb8a5beb91dabaffdb621712356fb6baca77b",
"body": null,
"is_bot": false,
"headline": "docs: update README and bump to 1.4.2",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-23T23:27:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e68d5dc75cb02412611bbab97b0663b3910b60f9",
"body": "Model type was never part of the deprecated old API — it's exported from\nthe root via types.ts re-export. No createModels() migration needed for\ntype-only usage.",
"is_bot": false,
"headline": "import Model from pi-ai root instead of /compat",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-23T18:56:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6a4bfb2891b557a280d26e5bbca31bf89f50548b",
"body": "- Swap Model imports from @earendil-works/pi-ai to /compat\n- Bump peer deps to ^0.80.1 (old >=0.74.0 with semver 0.x pinned to 0.75.x)\n- Add @earendil-works/pi-agent-core ^0.80.1 as direct dep\n- Fresh lockfile resolves all packages to 0.80.1",
"is_bot": false,
"headline": "migrate to pi-ai compat entrypoint and bump @earendil-works to 0.80.1",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-23T18:47:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2baa9b7819e56107ee5d61fe4b827f2883573c09",
"body": null,
"is_bot": false,
"headline": "docs: add fix-nudge-stale-pi lesson entry",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-22T22:35:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f1f90d2d364f0b5e9bcb2de2e82cab233149a931",
"body": null,
"is_bot": false,
"headline": "Merge branch 'issue/fix-nudge-stale-pi'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-22T20:24:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7bc6759c0ad38cc3755213299bb6ad9e626f73c7",
"body": "Remove getPiInstance() singleton call from emitIndividualNudge().\nInstead, store the ExtensionAPI passed to spawn() as an instance\nfield and refresh it on each call. This prevents stale pi references\nafter session lifecycle events (compaction, reload) that cause\nsilent nudge failures.\n\n- Add private\n[…]\n ExtensionAPI | null field, set in spawn()\n- Use this.pi in emitIndividualNudge() with null guard\n- Remove getPiInstance import from shell.js\n- Update tests to verify pi storage and null-skip behavior",
"is_bot": false,
"headline": "fix: store pi instance on SpawnCoordinator for fresh nudge delivery",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-22T20:18:57Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1f6e7234aa216bdb97dd1b1aafaf2183be62b6fc",
"body": null,
"is_bot": false,
"headline": "split on new line as well",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-22T13:13:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "48d9de27b956974c5ffe1b17f4df0ca5e8293594",
"body": "Instead of breaking mid-sentence when the buffer limit is reached,\nnow flushes up to the last sentence-ending punctuation (., !, ?).\n\nAlso removes 15 theater tests that only asserted on UI labels, values,\nand item ID existence without testing any behavior.",
"is_bot": false,
"headline": "feat: round thinking buffer flush to nearest sentence boundary",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-22T13:04:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1c9620284608c488cc8fd12fd4a5ed73c733d008",
"body": "…ssons entry",
"is_bot": false,
"headline": "rename thinking buffer label to 'Log file thinking buffer' and add le…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T21:53:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8caab7997754324cf3eac393cf1a7585f9deb00f",
"body": "…t ambiguity\n\nThe type·id separator was ambiguous — LLMs couldn't tell where the ID\nstarted. Agent tried agentId, then type·agentId, then just agentId\nsuccessfully. id (type) makes the ID unambiguous by placing it first.\n\nAgentStatus format: shortId (type) status\nStopAgent list: shortId (type), shortId (type)",
"is_bot": false,
"headline": "fix: flip agent display from type·id to id (type) to resolve StopAgen…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T21:52:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b48bdcb1f2edbcaa5e2d1b8e9017595346d2ddaf",
"body": null,
"is_bot": false,
"headline": "Merge branch 'issue/thinking-buffer-setting'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:53:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a4e44ec9686bee057b27024c07aafc74b1ecfb62",
"body": "Add outputThinkingBufferSize control to the widget settings menu.\nUser can select from OFF, 80, 200, 500, 1000 chars.\n\nChanges:\n- ConfigStore: add setOutputThinkingBufferSize mutation\n- Widget settings menu: add Thinking buffer ring toggle item\n- Mock setup: wire outputThinkingBufferSize through test store\n- Tests: coverage for config mutation and menu integration",
"is_bot": false,
"headline": "feat: add thinking buffer ring selector to widget settings",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:30:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f0a20398d7b5c218ac12a5b72df09359ee564dc9",
"body": null,
"is_bot": false,
"headline": "fix: flush worktree validation warnings via ctx.ui.notify on failure",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:25:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0ba6cd88db577d356f56132a39e8b45931ecfe54",
"body": null,
"is_bot": false,
"headline": "docs: add stale pi context lesson to lessons.md",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:24:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2565eafe026929ea5618a00e4de3ca13a6836288",
"body": null,
"is_bot": false,
"headline": "Merge branch 'issue/fix-stale-pi-context'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:19:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fb02e28ae09276c2cfdb8b961dc6c457f1c769fc",
"body": "Remove cached pi reference from SpawnCoordinator which could become stale\nafter session replacement/reload, causing uncaught exceptions when the\nnudge timer fires.\n\n- Remove this.pi field and pi parameter from constructor\n- Resolve pi via getPiInstance() at nudge emission time\n- Add disposed flag to skip nudge emission after dispose\n- Wrap sendMessage in try-catch as defense-in-depth\n- Update caller in events.ts",
"is_bot": false,
"headline": "fix: resolve stale pi crash in SpawnCoordinator nudge emission",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:19:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7de96d164c6f2a52ba93f8adffcd4845d70cc2b9",
"body": "Remove cached pi reference from SpawnCoordinator which could become stale\nafter session replacement/reload, causing uncaught exceptions when the\nnudge timer fires.\n\n- Remove this.pi field and pi parameter from constructor\n- Resolve pi via getPiInstance() at nudge emission time\n- Add disposed flag to skip nudge emission after dispose\n- Wrap sendMessage in try-catch as defense-in-depth\n- Update caller in events.ts",
"is_bot": false,
"headline": "fix: resolve stale pi crash in SpawnCoordinator nudge emission",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:14:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "30178b20f345c3f860e88e867ef5e64d5bb29025",
"body": "- Change error returned to LLM from vague 'git error: {msg}' to\n 'git rev-parse failed: {msg}' so the LLM knows which command failed\n- Add test that validates onWarning callback is invoked and warnings\n are flushed via ctx.ui.notify on validation failure",
"is_bot": false,
"headline": "refactor: improve git error message and add warning flush test",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T20:11:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "70ed9603a261862964c28ec2517b653ccbc03c68",
"body": null,
"is_bot": false,
"headline": "Fix tool tooltip",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T19:41:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1feb2077b5cfa441853a79a8617c9b7ab3ef272f",
"body": "thinking_start/delta/end are mutually exclusive assistantMessageEvent\ntypes. Chain them with else-if so the mutual exclusivity is explicit\ninstead of a standalone if followed by a separate if/else-if.",
"is_bot": false,
"headline": "refactor: chain thinking event branches with else-if in output-file.ts",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T19:37:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f73cff2ab0ded3611d6ed1e20b939cb8a0c9090c",
"body": "The old name implied errors. The new name reveals intent: it counts\nthinking blocks already written to the live stream, and is passed as\nthe skip count so the final turn_end flush does not re-emit them.",
"is_bot": false,
"headline": "refactor: rename streamedExceptionCount to streamedThinkingBlocks",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T19:36:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "72a13bfe5833b2199b8b002411d19d4776970bd6",
"body": "When thinking deltas accumulated below the buffer threshold and\nthinking_end arrived with the full block content, flushThinkingBuffer\nwrote the buffered tail but streamedThinkingChars was not updated.\nThe subsequent content.slice(streamedThinkingChars) then re-streamed\nfrom 0, duplicating the whole \n[…]\nength check and the duplicated accounting in\nthe delta path.\n\nThe existing 'flushes buffer on thinking_end' test hid the bug by using\nmismatched delta/end content; align the content and assert no dup.",
"is_bot": false,
"headline": "fix: duplicate thinking content when buffer flushes on thinking_end",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T19:35:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b322f645604dc3e3ca0967f2e49aa4b23c08f3ed",
"body": null,
"is_bot": false,
"headline": "Merge branch 'issue/stream-thinking-to-output'",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T14:50:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f8792e5a2c6f8f6b487e54400e5c3f4a0d1926d9",
"body": "flushThinkingBuffer and the thinking_end handler wrote content as a\nsingle line without splitting on newlines. Multi-line thinking content\nwould produce lines missing the [THINKING] prefix, violating the\nline-based format required for tail -f compatibility.\n\nUse the existing splitAndPrefix function which handles this correctly.\nAlso adds timestamps to each line of multi-line content, improving\nlog readability.",
"is_bot": false,
"headline": "refactor: use splitAndPrefix for thinking buffer flush in output-file.ts",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T14:42:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d9198f21d2cacaf14a06396c03f4fcd13a7c8c6b",
"body": "…ines when thinking_end never fires\n\n- Track thinking block state with thinkingBlockInProgress flag\n- Set flag true on thinking_start, false on thinking_end\n- At turn_end, if thinking_end never fired, increment streamedExceptionCount\n before flush to skip already-streamed thinking content\n- Add test case for missing thinking_end scenario",
"is_bot": false,
"headline": "fix: add thinkingBlockInProgress flag to prevent duplicate thinking l…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T14:12:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "79358ea62ce31c80b01cd3bda5f34a408d573862",
"body": "- thinking_end handler now flushes buffer before clearing it (was violating AC)\n- thinking_delta handler now tracks streamed chars for proper deduplication\n- deduplication test now fires thinking_end to properly test the logic",
"is_bot": false,
"headline": "fix: flush thinking buffer on thinking_end and fix deduplication test",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T13:58:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0dfb2497aeb58163548036b95f84b36f58218f96",
"body": "- Add config option outputThinkingBufferSize (default 0 = disabled)\n- When > 0, thinking deltas stream during message_update events\n- Buffer flushes when reaching configured size, newline, thinking_end, or turn_end\n- No duplicate thinking content at turn_end (already-streamed content skipped)\n- All existing tests pass, new tests added for streaming behavior",
"is_bot": false,
"headline": "feat: stream thinking blocks to output file in real-time",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-21T13:58:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a577ad00aafabd6d1fcab6666266220005d42121",
"body": "Extract a border() color helper and hoist the │ vertical bar and ─ horizontal\nbar out of the loop. Removes three repeated this.theme.fg('muted', ...) calls\nand a per-iteration allocation, without changing output.",
"is_bot": false,
"headline": "refactor: hoist border styling in ResultViewer render override",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-20T01:24:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f974be37d84decde74c5c89bd1eeae41d0d0c0c5",
"body": "The render override rendered children at innerWidth (width-2), then wrapped\neach line with '│ ' + line + ' │'. Since real Text pads every non-empty child\nline to the width it is given, content rows came back innerWidth wide and the\nbox added 4 more columns, making content rows width+2 while the top/\n[…]\ned width and that the\nright │ survives on content rows (short, full-width, and empty lines).\n\nAlso drop a duplicate expect(markdownRender).toHaveBeenCalled() in the\n'works with markdown content' test.",
"is_bot": false,
"headline": "fix: align box borders in ResultViewer render override",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-20T01:23:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9017ca3aeecb49eeb10519a8a9622bce33f09928",
"body": null,
"is_bot": false,
"headline": "Add back padding for result viewer",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-20T00:36:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "438b69170fa49edf38f3a150bf2c24812e6643ac",
"body": "…ialog/SelectOption\n\nThe dialog backs every search-backed menu (provider/model/type/worktree\nselection), not just model selection. Rename the symbols and move the\nfile from src/models/ to src/ui/ to reflect that it is a generic UI\nprimitive, not model-domain logic.\n\n- ModelSelectorDialog -> Searchab\n[…]\nelOption -> SelectOption\n- currentModel param -> currentValue\n- filterModels -> filterItems\n- src/models/model-selector.ts -> src/ui/searchable-select.ts\n\nImport sites and test mocks updated to match.",
"is_bot": false,
"headline": "refactor: rename ModelSelectorDialog/ModelOption to SearchableSelectD…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T20:24:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "eaaa149e5f6c1bdfe27e087618b6fe2c8d079287",
"body": "…ed menus\n\nThe search addition reused ModelSelectorDialog to pick providers, agent\ntypes, and worktrees, copy-pasting the same delegator-forward-declaration\ndance four times across three files. Extract one factory in helpers.ts\nthat owns the dialog+delegator wiring; onSelect may return a Component\nt\n[…]\nl pick (worktree picker).\n\nCollapse the two near-identical addModelLimitSubmenu / addProviderLimitSubmenu\nfactories in menu-concurrency into one addPickThenValueSubmenu parameterized\nby its item list.",
"is_bot": false,
"headline": "refactor(menu): extract createSearchableSelect helper for search-back…",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T20:16:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d335f770a7c3f9d48dfaad31cb6c069a5a336368",
"body": "The 'remove duplicate provider badge' fix dropped the provider field\nfrom provider/type list items, but ModelOption still required it, breaking\ntypecheck. The dialog already guards empty provider in rendering, so make\nthe field optional.",
"is_bot": false,
"headline": "fix(menu): make ModelOption.provider optional to match usage",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T20:14:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d856f7a6054ccc8e89c276b11c3db32f2666f91d",
"body": null,
"is_bot": false,
"headline": "fix(menu): remove duplicate provider badge from provider/type lists",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T20:09:15Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8fdfe86a5a60fb6aff7092017a85587e81cbd5cd",
"body": null,
"is_bot": false,
"headline": "fix(menu): hide empty provider badge in ModelSelectorDialog",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T20:07:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "03849d7c37d86c0b146cd09e4a954ca2a82cde8c",
"body": null,
"is_bot": false,
"headline": "feat(menu): add search to type selection and worktree picker",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T20:05:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "60ffe42e64b72ec824dc2a11266c56354664a498",
"body": null,
"is_bot": false,
"headline": "feat(menu): add search to provider selection in concurrency settings",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T19:57:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "faaff6c90061f5c6b2ac9755b1c604bc1758ecab",
"body": null,
"is_bot": false,
"headline": "feat(menu): add search to model selection in concurrency settings",
"author_name": "Alexander Paramonov",
"author_login": "AlexParamonov",
"committed_at": "2026-06-19T19:54:32Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 0,
"commits_last_year": 493,
"latest_release_at": null,
"latest_release_tag": null,
"releases_from_tags": false,
"days_since_last_push": 0,
"active_weeks_last_year": 9,
"days_since_latest_release": null,
"mean_days_between_releases": null
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": false,
"has_contributing": false,
"health_percentage": 28,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "pi-subagents-lite",
"exists": true,
"license": "MIT",
"keywords": [
"pi-package",
"pi",
"pi-agent",
"pi-coding-agent",
"pi-extension",
"subagents",
"ai",
"agents"
],
"ecosystem": "npm",
"matches_repo": true,
"registry_url": "https://www.npmjs.com/package/pi-subagents-lite",
"is_deprecated": false,
"latest_version": "1.4.10",
"repository_url": "https://github.com/AlexParamonov/pi-subagents-lite",
"versions_count": 22,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": 1,
"monthly_downloads": 2122,
"first_published_at": "2026-05-26T16:40:31.915000Z",
"latest_published_at": "2026-07-17T19:56:32.030000Z",
"latest_version_yanked": null,
"days_since_latest_publish": 5
}
]
},
"popularity": {
"forks": 5,
"stars": 14,
"watchers": 0,
"fork_history": {
"days": [
{
"date": "2026-07-07",
"count": 1
},
{
"date": "2026-07-12",
"count": 2
},
{
"date": "2026-07-20",
"count": 1
}
],
"complete": true,
"collected": 4,
"total_forks": 5
},
"star_history": null,
"open_issues_and_prs": 1
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"tsconfig.json"
],
"toolchain_manifests": [],
"largest_source_bytes": 65026,
"source_files_sampled": 93,
"oversized_source_files": 1,
"agent_instruction_files": [
"AGENTS.md"
],
"agent_instruction_max_bytes": 195
},
"dependencies": {
"manifests": [
"package.json"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"npm"
],
"dependencies": [
{
"name": "@earendil-works/pi-agent-core",
"manifest": "package.json",
"ecosystem": "npm",
"version_constraint": "^0.80.10"
},
{
"name": "@sinclair/typebox",
"manifest": "package.json",
"ecosystem": "npm",
"version_constraint": "^0.34.49"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 0,
"open_issues": 1,
"closed_ratio": 0.857,
"closed_issues": 6,
"closed_unmerged_prs": 1
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "AlexParamonov",
"commits": 491,
"avatar_url": "https://avatars.githubusercontent.com/u/352030?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": false,
"has_tests": true,
"ci_workflows": [],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": null,
"reason": "no workflows found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": null,
"reason": "no dependencies found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": null,
"reason": "No tokens found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 8,
"reason": "2 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "5057ae195a4928628428c1ab1196c05f9a837b99",
"ran_at": "2026-07-23T03:20:28Z",
"aggregate_score": 2.4,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": null,
"oldest_open_prs": [],
"last_merged_pr_at": null,
"ci_last_conclusion": null,
"oldest_open_issues": [
{
"number": 4,
"created_at": "2026-06-17T01:12:40Z",
"last_comment_at": "2026-06-21T11:26:36Z",
"last_comment_author": "AlexParamonov"
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/AlexParamonov/pi-subagents-lite",
"host": "github.com",
"name": "pi-subagents-lite",
"owner": "AlexParamonov"
},
"metrics": {
"overall": {
"key": "overall",
"band": "at_risk",
"name": "Overall health",
"note": null,
"notes": [],
"value": 39,
"inputs": {
"security": 24,
"vitality": 36,
"community": 41,
"governance": 47,
"engineering": 44
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "at_risk",
"name": "Vitality",
"value": 36,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 60,
"inputs": {
"commits_last_year": 493,
"human_commit_share": 1,
"days_since_last_push": 0,
"active_weeks_last_year": 9
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "9/52 weeks with commits",
"points": 6.2,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 9
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "493 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 493
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "critical",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 1,
"inputs": {
"releases_count": 0
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "no releases published",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_releases_published",
"params": {}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "no releases",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_releases",
"params": {}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "no releases",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_releases",
"params": {}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 41,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 23,
"inputs": {
"forks": 5,
"stars": 14,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "14 stars",
"points": 18.1,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 14
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "5 forks",
"points": 5,
"status": "partial",
"details": [
{
"code": "forks",
"params": {
"count": 5
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
},
{
"key": "ecosystem_adoption",
"band": "moderate",
"name": "Ecosystem adoption (downloads)",
"note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"registry_dependents"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 56,
"inputs": {
"packages": [
"pi-subagents-lite"
],
"dependents": null,
"ecosystems": "npm",
"total_downloads": null,
"monthly_downloads": 2122
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "2,122 downloads/month across npm",
"points": 44.4,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 2122,
"ecosystems": "npm"
}
}
],
"max_points": 80
},
{
"key": "registry_dependents",
"name": "Registry dependents",
"detail": "not reported by this ecosystem",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_reported_by_this_ecosystem",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 47,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 10,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "at_risk",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"merged_prs": 0,
"open_issues": 1,
"closed_issues": 6,
"issue_closed_ratio": 0.857,
"closed_unmerged_prs": 1
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "86% of issues closed",
"points": 40.1,
"status": "partial",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 86
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "0/1 decided PRs merged",
"points": 0,
"status": "missed",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 0,
"decided": 1
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 55,
"inputs": {
"followers": 19,
"owner_type": "User",
"is_verified": null,
"owner_login": "AlexParamonov",
"public_repos": 58,
"account_age_days": 5833
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "personal (user) account",
"points": 10,
"status": "partial",
"details": [
{
"code": "owner_personal",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": "not applicable to user accounts",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_applicable_to_user_accounts",
"params": {}
}
],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "19 followers of AlexParamonov",
"points": 9.4,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 19,
"login": "AlexParamonov"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "58 public repos, account ~15 yr old",
"points": 24.9,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 58
}
},
{
"code": "account_age_years",
"params": {
"years": 15
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"pi-subagents-lite"
],
"ecosystems": "npm",
"any_deprecated": false,
"min_days_since_publish": 5
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on npm",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "npm"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 5 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 5
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "22 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 22
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "at_risk",
"name": "Engineering Quality",
"value": 44,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "at_risk",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 30,
"inputs": {
"has_ci": false,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "moderate",
"name": "Documentation",
"note": null,
"notes": [],
"value": 65,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": null,
"has_readme": true,
"has_docs_dir": true,
"has_description": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "critical",
"name": "Security",
"value": 24,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "critical",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"dangerous_workflow",
"packaging",
"pinned_dependencies",
"signed_releases",
"token_permissions"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 24,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 12,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 6,
"scorecard_aggregate": 2.4
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no workflows found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "no dependencies found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "No tokens found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "2 existing vulnerabilities detected",
"points": 6,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "moderate",
"name": "AI Readiness",
"value": 55,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "moderate",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 58,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.83,
"agent_instruction_files": [
"AGENTS.md"
],
"agent_instruction_max_bytes": 195
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "AGENTS.md (stub)",
"points": 18,
"status": "partial",
"details": [
{
"code": "file_list",
"params": {
"files": "AGENTS.md"
}
},
{
"code": "agent_instructions_stub",
"params": {}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "83 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 83,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "at_risk",
"name": "Verify loop (build / test / typecheck)",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_pinned_dependencies"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 37,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [
"tsconfig.json"
],
"agent_commit_share": 0,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "no dependencies found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 99,
"inputs": {
"primary_language": "TypeScript",
"largest_source_bytes": 65026,
"source_files_sampled": 93,
"oversized_source_files": 1
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "TypeScript (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "TypeScript"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "1/93 source files over 60KB",
"points": 54.4,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 93,
"oversized": 1
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"deps.dev does not index npm:pi-subagents-lite@1.4.10; advisories assessed against the repository dependency graph instead"
],
"report_type": "repository",
"generated_at": "2026-07-23T03:20:33.461719Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/AlexParamonov/pi-subagents-lite.svg",
"full_name": "AlexParamonov/pi-subagents-lite",
"license_state": "standard",
"license_spdx": "MIT"
}