Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ecdcc5d
chore(deps-ci): bump github/codeql-action from 4.37.9 to 4.38.0 (#412)
dependabot[bot] Sep 12, 2026
d90187d
chore(dist): rebuild 2.28.0-develop.ecdcc5d [skip ci]
github-actions[bot] Sep 12, 2026
936abc3
fix(opengist): add default TTL for opengist uploads
shaftoe Sep 15, 2026
ec963b9
chore(dist): rebuild 2.28.0-develop.936abc3 [skip ci]
github-actions[bot] Sep 15, 2026
853a9af
chore(release): 2.28.1 [skip ci]
semantic-release-bot Sep 15, 2026
28eb55e
fix(README.md): add checkout action to interactive workflow sample (#…
knocte Sep 20, 2026
f9b68d6
chore(dist): rebuild 2.28.1-develop.28eb55e [skip ci]
github-actions[bot] Sep 20, 2026
d9a496a
fix(deps): bump Pi sdk to v0.86.0, remove obsolete patchSDKLoaderSource
shaftoe Sep 20, 2026
c6d0453
chore(dist): rebuild 2.28.1-develop.d9a496a [skip ci]
github-actions[bot] Sep 20, 2026
f20fb47
chore: update README deps [skip ci]
github-actions[bot] Sep 20, 2026
738fd4f
feat: add cache_warming input and summarize_text tool
shaftoe Sep 20, 2026
7c2b842
chore(dist): rebuild 2.28.1-develop.738fd4f [skip ci]
github-actions[bot] Sep 20, 2026
1397590
fix: ensure yaml is properly formatted
shaftoe Sep 21, 2026
2f5c026
chore(dist): rebuild 2.28.1-develop.1397590 [skip ci]
github-actions[bot] Sep 21, 2026
1f47573
chore(deps): bump Pi sdk to v0.87.0
shaftoe Sep 22, 2026
b85e45b
chore(dist): rebuild 2.28.1-develop.1f47573 [skip ci]
github-actions[bot] Sep 22, 2026
812ea1f
chore: update README deps [skip ci]
github-actions[bot] Sep 22, 2026
8faf601
chore(release): 2.29.0 [skip ci]
semantic-release-bot Sep 22, 2026
e87a919
ci: replace dependabot with renovate
shaftoe Sep 22, 2026
4d8ed57
chore(dist): rebuild 2.29.0-develop.e87a919 [skip ci]
github-actions[bot] Sep 22, 2026
ab6dba7
chore: update renovate.json
shaftoe Sep 22, 2026
a15107d
chore(dist): rebuild 2.29.0-develop.ab6dba7 [skip ci]
github-actions[bot] Sep 22, 2026
19f3233
fix: refresh model catalog from pi.dev at startup (#416)
maximilianzuern Sep 25, 2026
0d2c364
chore(dist): rebuild 2.29.0-develop.19f3233 [skip ci]
github-actions[bot] Sep 25, 2026
334c336
fix: add opt-out for model auto refresh
shaftoe Sep 25, 2026
679dd18
chore(dist): rebuild 2.29.0-develop.334c336 [skip ci]
github-actions[bot] Sep 25, 2026
47a74de
fix: get_ci_status uses the current PR head by default (#417)
maximilianzuern Sep 25, 2026
d1cea1d
chore(dist): rebuild 2.29.0-develop.47a74de [skip ci]
github-actions[bot] Sep 25, 2026
9a813ae
ci: remove renovate flow, use renovate app
shaftoe Sep 26, 2026
7e21f62
chore(dist): rebuild 2.29.0-develop.9a813ae [skip ci]
github-actions[bot] Sep 26, 2026
473a22e
chore: update README, remove broken link
shaftoe Sep 27, 2026
dea3d49
chore(dist): rebuild 2.29.0-develop.473a22e [skip ci]
github-actions[bot] Sep 27, 2026
9706e28
chore(deps): bump Pi to v0.87.1
shaftoe Sep 28, 2026
1d680d5
chore(dist): rebuild 2.29.0-develop.9706e28 [skip ci]
github-actions[bot] Sep 28, 2026
e0b04b5
chore: update README deps [skip ci]
github-actions[bot] Sep 28, 2026
babaa1a
chore(release): 2.29.1 [skip ci]
semantic-release-bot Sep 28, 2026
f554387
Create PRs in a fork if insufficient permissions
webwarrior-ws Sep 9, 2026
b4c9f7b
Implement tools support for creating PR in a fork
webwarrior-ws Sep 15, 2026
577f8c3
chore(dist): rebuild
webwarrior-ws Sep 17, 2026
59b6873
Improved code coverage
webwarrior-ws Sep 30, 2026
1aafd08
chore(dist): rebuild
webwarrior-ws Sep 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .github/dependabot.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/fallow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ jobs:

- name: Upload SARIF to Code Scanning
if: always()
uses: github/codeql-action/upload-sarif@v4.37.9
uses: github/codeql-action/upload-sarif@v4.38.0
with:
sarif_file: fallow-results.sarif
44 changes: 43 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.29.1] - 2026-09-28

### Changed

- **deps**: bump Pi to v0.87.1

### Fixed

- add opt-out for model auto refresh
- get_ci_status uses the current PR head by default (#417)
- refresh model catalog from pi.dev at startup (#416)

## [2.29.0] - 2026-09-22

### Added

- add cache_warming input and summarize_text tool

### Changed

- **deps**: bump Pi sdk to v0.87.0

### Fixed

- **README.md**: add checkout action to interactive workflow sample (#414)
- **deps**: bump Pi sdk to v0.86.0, remove obsolete patchSDKLoaderSource
- ensure yaml is properly formatted

## [2.28.1] - 2026-09-15

### Changed

- **deps-ci**: bump github/codeql-action from 4.37.9 to 4.38.0 (#412)
- **deps-dev**: bump vitest from 4.1.10 to 4.1.11 (#410)

### Fixed

- **opengist**: add default TTL for opengist uploads

## [2.28.0] - 2026-09-08

### Added
Expand Down Expand Up @@ -662,7 +701,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- README link corrections
- Codecov action updated, removed double build

[unreleased]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.28.0...HEAD
[unreleased]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.29.1...HEAD
[2.29.1]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.29.0...v2.29.1
[2.29.0]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.28.1...v2.29.0
[2.28.1]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.28.0...v2.28.1
[2.28.0]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.27.1...v2.28.0
[2.27.1]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.27.0...v2.27.1
[2.27.0]: https://github.com/shaftoe/pi-coding-agent-action/compare/v2.26.0...v2.27.0
Expand Down
81 changes: 68 additions & 13 deletions README.md

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ branding:

inputs:
github_token:
description: 'GitHub token for API access. The default `GITHUB_TOKEN` works for all standard operations. To use `share_session`, provide a classic PAT (`gist` scope), fine-grained PAT (Account → Gists: read/write), or GitHub App token instead — the default `GITHUB_TOKEN` cannot create gists.'
description: 'GitHub token for API access. The default `GITHUB_TOKEN` works for all standard operations. To use `share_session`, provide a classic PAT (`gist` scope), fine-grained PAT (Account → Gists: read/write), or GitHub App token instead — the default `GITHUB_TOKEN` cannot create gists. To open pull requests from the agent''s own fork, a personal access token needs to be classic PAT with `repo` scope, or a fine-grained PAT with repository read/write + fork permissions.'
required: true

provider:
Expand Down Expand Up @@ -105,11 +105,26 @@ inputs:
required: false
default: ''

share_gist_expiration:
description: 'Time-to-live for shared gists (opengist provider only; GitHub Gists have no expiry). One of `1hour`, `12hours`, `1day`, `7days`, `15days`, or `never`. Defaults to `7days` — shared sessions are ephemeral CI artifacts. Set to `never` to keep them indefinitely.'
required: false
default: ''

auto_compaction:
description: 'Enable automatic context compaction when the conversation grows too large for the model context window. When enabled, Pi will summarize older messages to free up context space, allowing longer sessions without hitting context limits.'
required: false
default: 'false'

cache_warming:
description: 'Prompt cache-warming mode. Keeps expensive prompt-cache prefixes alive with cost-aware one-token refreshes so pauses (e.g. long tool runs) don''t pay full input price again. One of `off`, `streaming` (refresh during long tool executions; the default), or `idle` (also refresh between prompts). Refreshes are billed as a cache read plus one output token and only fire when expected savings exceed the cost.'
required: false
default: ''

refresh_model_catalog:
description: 'Whether to refresh the provider''s model catalog from pi.dev at startup so models newer than the bundled SDK resolve. Set to `false` to skip the network round-trip and shorten boot time (the bundled model list is used instead).'
required: false
default: 'true'

pr_number:
description: 'Pull request number to target. Use this with workflow_dispatch to run the agent on a specific PR without a triggering event. When set, the action fetches PR context and posts the result as a comment on the specified PR.'
required: false
Expand Down
3,435 changes: 1,737 additions & 1,698 deletions dist/index.js

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion dist/pi-sdk/dist/core/export-html/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@
case 'thinking_level_change':
parts.push('thinking', entry.thinkingLevel);
break;
case 'context_edit':
parts.push('context edit', entry.replacement === null ? 'omit' : 'replace', entry.targetId);
break;
}

return parts.join(' ').toLowerCase();
Expand Down Expand Up @@ -385,7 +388,7 @@
}

// Apply filter mode
const isSettingsEntry = ['label', 'custom', 'model_change', 'thinking_level_change'].includes(entry.type);
const isSettingsEntry = ['label', 'custom', 'context_edit', 'model_change', 'thinking_level_change'].includes(entry.type);
let passesFilter = true;

switch (filterMode) {
Expand Down Expand Up @@ -696,6 +699,8 @@
return labelHtml + `<span class="tree-muted">[model: ${escapeHtml(entry.modelId)}]</span>`;
case 'thinking_level_change':
return labelHtml + `<span class="tree-muted">[thinking: ${escapeHtml(entry.thinkingLevel)}]</span>`;
case 'context_edit':
return labelHtml + `<span class="tree-muted">[context ${entry.replacement === null ? 'omit' : 'replace'}: ${escapeHtml(entry.targetId)}]</span>`;
default:
return labelHtml + `<span class="tree-muted">[${escapeHtml(entry.type)}]</span>`;
}
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pi-coding-agent-action",
"version": "2.28.0",
"version": "2.29.1",
"private": true,
"description": "CI/CD Action to integrate Pi coding agent in workflows",
"scripts": {
Expand Down Expand Up @@ -42,9 +42,9 @@
"dependencies": {
"@alexanderfortin/pi-orchestrator": "workspace:*",
"@alexanderfortin/pi-platform-github": "workspace:*",
"@earendil-works/pi-agent-core": "^0.85.1",
"@earendil-works/pi-ai": "^0.85.1",
"@earendil-works/pi-coding-agent": "^0.85.1"
"@earendil-works/pi-agent-core": "^0.87.1",
"@earendil-works/pi-ai": "^0.87.1",
"@earendil-works/pi-coding-agent": "^0.87.1"
},
"devDependencies": {
"@actions/github": "^9.1.1",
Expand All @@ -65,6 +65,7 @@
"semantic-release": "^25.0.8",
"tsx": "^4.20.3",
"typescript": "~6.0.3",
"vitest": "^4.1.11"
"vitest": "^4.1.11",
"yaml": "^2.4.0"
}
}
4 changes: 2 additions & 2 deletions packages/pi-action-bridge/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@alexanderfortin/pi-action-bridge",
"private": true,
"version": "2.28.0",
"version": "2.29.1",
"type": "module",
"keywords": [
"pi-package"
Expand All @@ -14,7 +14,7 @@
"simple-git": "^3.36.0"
},
"devDependencies": {
"@earendil-works/pi-coding-agent": "^0.85.1",
"@earendil-works/pi-coding-agent": "^0.87.1",
"typebox": "^1.3.6"
},
"pi": {
Expand Down
8 changes: 4 additions & 4 deletions packages/pi-action/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alexanderfortin/pi-action",
"version": "2.28.0",
"version": "2.29.1",
"private": true,
"type": "module",
"main": "dist/index.js",
Expand All @@ -14,9 +14,9 @@
"@actions/github": "^9.1.1",
"@alexanderfortin/pi-orchestrator": "workspace:*",
"@alexanderfortin/pi-platform-github": "workspace:*",
"@earendil-works/pi-agent-core": "^0.85.1",
"@earendil-works/pi-ai": "^0.85.1",
"@earendil-works/pi-coding-agent": "^0.85.1",
"@earendil-works/pi-agent-core": "^0.87.1",
"@earendil-works/pi-ai": "^0.87.1",
"@earendil-works/pi-coding-agent": "^0.87.1",
"@js-temporal/polyfill": "^0.5.1"
},
"devDependencies": {
Expand Down
48 changes: 13 additions & 35 deletions packages/pi-action/scripts/package.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
import { build, type Plugin } from 'esbuild';
import { copyFileSync, existsSync, mkdirSync, rmSync } from 'node:fs';
import { build } from 'esbuild';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { resolvePiSdkPackagePath } from './pi-sdk';
Expand Down Expand Up @@ -45,33 +45,14 @@ export {
* This patch can be removed once the SDK uses virtual modules for bundled Node
* by default.
*/
const SDK_LOADER_NODE_BRANCH = /: \{ alias: getAliases\(\) \}\),/;

/** Apply the bundled Node extension-loader patch to SDK source. */
export function patchSDKLoaderSource(source: string): string {
const patched = source.replace(
SDK_LOADER_NODE_BRANCH,
': { virtualModules: VIRTUAL_MODULES, tryNative: false }),'
);
if (patched === source) {
throw new Error(
'[patch-sdk-loader] Bundled Node extension loader pattern not matched; the SDK may have changed.'
);
}
return patched;
}

function patchSDKLoaderPlugin(): Plugin {
return {
name: 'patch-sdk-loader',
setup(build) {
build.onLoad({ filter: /extensions\/loader\.js$/ }, async args => ({
contents: patchSDKLoaderSource(readFileSync(args.path, 'utf-8')),
loader: 'js',
}));
},
};
}
/**
* Since pi-coding-agent 0.86.0 the SDK natively uses virtual modules (and
* `tryNative: false`) for bundled Node builds when the build-time
* `PI_BUNDLED_NODE` define is set — the same mechanism it already used for
* Bun binaries. Defining it here keeps jiti resolving npm extensions' Pi peer
* dependencies against the bundled host runtime instead of the temporary
* installation directory. (Replaces the former source patch of loader.js.)
*/

/**
* Pi SDK runtime assets that must be copied to `dist/pi-sdk/` because they're
Expand All @@ -92,11 +73,7 @@ const SDK_ASSETS: ReadonlyArray<readonly [string, readonly string[]]> = [
* Copy a single SDK asset directory, creating the destination as needed and
* silently skipping missing source files. Exported for unit testing.
*/
export function copySdkAssetDir(
srcDir: string,
destDir: string,
files: readonly string[]
): void {
export function copySdkAssetDir(srcDir: string, destDir: string, files: readonly string[]): void {
if (!existsSync(srcDir)) return;
mkdirSync(destDir, { recursive: true });
for (const file of files) {
Expand Down Expand Up @@ -139,11 +116,12 @@ export async function buildDist(cwd: string = process.cwd()): Promise<void> {
outfile: join(cwd, 'dist/index.js'),
format: 'cjs',
minify: true,
plugins: [patchSDKLoaderPlugin()],
plugins: [],
define: {
'import.meta.url': 'importMetaUrl',
__PI_CODING_AGENT_VERSION__: JSON.stringify(piVersion),
__VERSION__: JSON.stringify(version),
PI_BUNDLED_NODE: 'true',
},
inject: [join(cwd, 'packages/pi-action/src/import-meta-url.js')],
});
Expand Down
65 changes: 64 additions & 1 deletion packages/pi-action/src/adapters/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/**
* @file GitHub Actions configuration adapter.
*
Expand All @@ -18,7 +18,14 @@
*/

import * as core from '@actions/core';
import type { PiConfig } from '@alexanderfortin/pi-orchestrator';
import type { OpengistExpiration, PiConfig } from '@alexanderfortin/pi-orchestrator';
import {
DEFAULT_OPENGIST_EXPIRATION,
OPENGIST_EXPIRATIONS,
} from '@alexanderfortin/pi-orchestrator';

/** Valid values for the `cache_warming` input (mirrors the SDK's modes). */
export const CACHE_WARMING_MODES = ['off', 'streaming', 'idle'] as const;

// ---------------------------------------------------------------------------
// Error message constants — keep stable; they are part of the public
Expand Down Expand Up @@ -106,6 +113,35 @@
return tools.length > 0 ? [...new Set(tools)] : undefined;
}

/**
* Parse the `share_gist_expiration` input into an Opengist TTL preset.
*
* Returns `undefined` for empty input (the provider then applies its 7-day
* default) and for unrecognised values (a warning is emitted by the caller so
* a typo doesn't silently change the TTL). Matching is case-insensitive and
* whitespace-trimmed.
*/
export function parseGistExpiration(raw: string): OpengistExpiration | undefined {
const normalized = raw.trim().toLowerCase();
return (OPENGIST_EXPIRATIONS as readonly string[]).includes(normalized)
? (normalized as OpengistExpiration)
: undefined;
}

/**
* Parse the `cache_warming` input into a prompt cache-warming mode.
*
* Returns `undefined` for empty input (the SDK then applies its default,
* `"streaming"`) and for unrecognised values (a warning is emitted by the
* caller so a typo doesn't silently change behavior). Case-insensitive.
*/
export function parseCacheWarmingMode(raw: string): PiConfig['cacheWarming'] {
const normalized = raw.trim().toLowerCase();
return (CACHE_WARMING_MODES as readonly string[]).includes(normalized)
? (normalized as PiConfig['cacheWarming'])
: undefined;
}

// ---------------------------------------------------------------------------
// Validation
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -168,6 +204,18 @@
const exportSessionJsonl = parseBooleanInput(core.getInput('export_session_jsonl'), false);
const autoCompaction = parseBooleanInput(core.getInput('auto_compaction'), false);
const shareSession = parseBooleanInput(core.getInput('share_session'), false);
const refreshModelCatalog = parseBooleanInput(core.getInput('refresh_model_catalog'), true);

// --- Prompt cache warming -----------------------------------------------
const cacheWarmingRaw = core.getInput('cache_warming');
const cacheWarming = parseCacheWarmingMode(cacheWarmingRaw);
if (cacheWarmingRaw.trim() && !cacheWarming) {
core.warning(
`Unknown cache_warming "${cacheWarmingRaw.trim()}". ` +
`Valid values are: ${CACHE_WARMING_MODES.join(', ')}. ` +
'Falling back to the SDK default ("streaming").'
);
}

// --- Session sharing storage backend inputs ---------------------------
const shareGistProviderRaw = core.getInput('share_gist_provider').trim().toLowerCase();
Expand All @@ -192,6 +240,18 @@
if (shareGistToken) {
core.setSecret(shareGistToken);
}
// TTL preset for shared Opengist gists. Unset → undefined so the provider's
// 7-day default applies; an unrecognised value warns and also falls back to
// that default rather than sending a value the server would reject.
const shareGistExpirationRaw = core.getInput('share_gist_expiration');
const shareGistExpiration = parseGistExpiration(shareGistExpirationRaw);
if (shareGistExpirationRaw.trim() && !shareGistExpiration) {
core.warning(
`Unknown share_gist_expiration "${shareGistExpirationRaw.trim()}"; ` +
`defaulting to ${DEFAULT_OPENGIST_EXPIRATION}. ` +
`Valid values are: ${OPENGIST_EXPIRATIONS.join(', ')}.`
);
}

// --- Optional positive-integer inputs ----------------------------------
const diffMaxLines = parsePositiveIntInput(core.getInput('diff_max_lines'));
Expand Down Expand Up @@ -220,10 +280,13 @@
exportSessionHtml,
exportSessionJsonl,
autoCompaction,
...(cacheWarming ? { cacheWarming } : {}),
refreshModelCatalog,
shareSession,
...(shareGistProvider ? { shareGistProvider } : {}),
...(shareGistApiUrl ? { shareGistApiUrl } : {}),
...(shareGistToken ? { shareGistToken } : {}),
...(shareGistExpiration ? { shareGistExpiration } : {}),
...(githubToken ? { githubToken } : {}),
...(diffMaxLines ? { diffMaxLines } : {}),
...(diffMaxBytes ? { diffMaxBytes } : {}),
Expand Down
Loading
Loading