@oh-my-pi/pi-coding-agent 8.0.20 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/package.json +14 -11
- package/scripts/generate-wasm-b64.ts +24 -0
- package/src/capability/context-file.ts +1 -1
- package/src/capability/extension-module.ts +1 -1
- package/src/capability/extension.ts +1 -1
- package/src/capability/hook.ts +1 -1
- package/src/capability/instruction.ts +1 -1
- package/src/capability/mcp.ts +1 -1
- package/src/capability/prompt.ts +1 -1
- package/src/capability/rule.ts +1 -1
- package/src/capability/settings.ts +1 -1
- package/src/capability/skill.ts +1 -1
- package/src/capability/slash-command.ts +1 -1
- package/src/capability/ssh.ts +1 -1
- package/src/capability/system-prompt.ts +1 -1
- package/src/capability/tool.ts +1 -1
- package/src/cli/args.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -5
- package/src/commit/agentic/agent.ts +309 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +359 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +26 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +40 -0
- package/src/commit/agentic/state.ts +74 -0
- package/src/commit/agentic/tools/analyze-file.ts +131 -0
- package/src/commit/agentic/tools/git-file-diff.ts +194 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +84 -0
- package/src/commit/agentic/tools/index.ts +56 -0
- package/src/commit/agentic/tools/propose-changelog.ts +128 -0
- package/src/commit/agentic/tools/propose-commit.ts +154 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/split-commit.ts +284 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +200 -0
- package/src/commit/analysis/conventional.ts +169 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +114 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +36 -0
- package/src/commit/changelog/generate.ts +112 -0
- package/src/commit/changelog/index.ts +233 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +93 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/git/errors.ts +11 -0
- package/src/commit/git/index.ts +217 -0
- package/src/commit/git/operations.ts +53 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
- package/src/commit/map-reduce/index.ts +63 -0
- package/src/commit/map-reduce/map-phase.ts +193 -0
- package/src/commit/map-reduce/reduce-phase.ts +147 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +84 -0
- package/src/commit/pipeline.ts +242 -0
- package/src/commit/prompts/analysis-system.md +155 -0
- package/src/commit/prompts/analysis-user.md +41 -0
- package/src/commit/prompts/changelog-system.md +56 -0
- package/src/commit/prompts/changelog-user.md +19 -0
- package/src/commit/prompts/file-observer-system.md +26 -0
- package/src/commit/prompts/file-observer-user.md +9 -0
- package/src/commit/prompts/reduce-system.md +60 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +4 -0
- package/src/commit/prompts/summary-system.md +52 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/types.ts +109 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/config/file-lock.ts +111 -0
- package/src/config/model-registry.ts +16 -7
- package/src/config/settings-manager.ts +115 -40
- package/src/config.ts +5 -5
- package/src/discovery/agents-md.ts +1 -1
- package/src/discovery/builtin.ts +1 -1
- package/src/discovery/claude.ts +1 -1
- package/src/discovery/cline.ts +1 -1
- package/src/discovery/codex.ts +1 -1
- package/src/discovery/cursor.ts +1 -1
- package/src/discovery/gemini.ts +1 -1
- package/src/discovery/github.ts +1 -1
- package/src/discovery/index.ts +11 -11
- package/src/discovery/mcp-json.ts +1 -1
- package/src/discovery/ssh.ts +1 -1
- package/src/discovery/vscode.ts +1 -1
- package/src/discovery/windsurf.ts +1 -1
- package/src/extensibility/custom-commands/loader.ts +1 -1
- package/src/extensibility/custom-commands/types.ts +1 -1
- package/src/extensibility/custom-tools/loader.ts +1 -1
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/loader.ts +1 -1
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/loader.ts +1 -1
- package/src/extensibility/hooks/types.ts +3 -3
- package/src/index.ts +10 -10
- package/src/ipy/executor.ts +97 -1
- package/src/lsp/index.ts +1 -1
- package/src/lsp/render.ts +90 -46
- package/src/main.ts +16 -3
- package/src/mcp/loader.ts +3 -3
- package/src/migrations.ts +3 -3
- package/src/modes/components/assistant-message.ts +29 -1
- package/src/modes/components/tool-execution.ts +5 -3
- package/src/modes/components/tree-selector.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +5 -3
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-mode.ts +1 -4
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/theme/mermaid-cache.ts +89 -0
- package/src/modes/theme/theme.ts +2 -0
- package/src/modes/types.ts +2 -2
- package/src/patch/index.ts +3 -9
- package/src/patch/shared.ts +33 -5
- package/src/prompts/tools/task.md +2 -0
- package/src/sdk.ts +60 -22
- package/src/session/agent-session.ts +3 -3
- package/src/session/agent-storage.ts +32 -28
- package/src/session/artifacts.ts +24 -1
- package/src/session/auth-storage.ts +25 -10
- package/src/session/storage-migration.ts +12 -53
- package/src/system-prompt.ts +2 -2
- package/src/task/.executor.ts.kate-swp +0 -0
- package/src/task/executor.ts +1 -1
- package/src/task/index.ts +10 -1
- package/src/task/output-manager.ts +94 -0
- package/src/task/render.ts +7 -12
- package/src/task/worker.ts +1 -1
- package/src/tools/ask.ts +35 -13
- package/src/tools/bash.ts +80 -87
- package/src/tools/calculator.ts +42 -40
- package/src/tools/complete.ts +1 -1
- package/src/tools/fetch.ts +67 -104
- package/src/tools/find.ts +83 -86
- package/src/tools/grep.ts +80 -96
- package/src/tools/index.ts +10 -7
- package/src/tools/ls.ts +39 -65
- package/src/tools/notebook.ts +48 -64
- package/src/tools/output-utils.ts +1 -1
- package/src/tools/python.ts +71 -183
- package/src/tools/read.ts +74 -15
- package/src/tools/render-utils.ts +1 -15
- package/src/tools/ssh.ts +43 -24
- package/src/tools/todo-write.ts +27 -15
- package/src/tools/write.ts +93 -64
- package/src/tui/code-cell.ts +115 -0
- package/src/tui/file-list.ts +48 -0
- package/src/tui/index.ts +11 -0
- package/src/tui/output-block.ts +73 -0
- package/src/tui/status-line.ts +40 -0
- package/src/tui/tree-list.ts +56 -0
- package/src/tui/types.ts +17 -0
- package/src/tui/utils.ts +49 -0
- package/src/vendor/photon/photon_rs_bg.wasm.b64.js +1 -0
- package/src/web/search/auth.ts +1 -1
- package/src/web/search/index.ts +1 -1
- package/src/web/search/render.ts +119 -163
- package/tsconfig.json +0 -42
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
You are an expert changelog writer who analyzes git diffs and produces Keep a Changelog entries. Get this right—changelogs are how users understand what changed.
|
|
2
|
+
|
|
3
|
+
<instructions>
|
|
4
|
+
Analyze the diff and return JSON changelog entries.
|
|
5
|
+
|
|
6
|
+
1. Identify user-visible changes only
|
|
7
|
+
2. Categorize each change (Added, Changed, Deprecated, Removed, Fixed, Security, Breaking Changes)
|
|
8
|
+
3. Write entries starting with past-tense verb describing user impact
|
|
9
|
+
4. Omit categories with no entries
|
|
10
|
+
5. Return empty entries object for internal-only changes
|
|
11
|
+
|
|
12
|
+
This matters. Be thorough but precise.
|
|
13
|
+
</instructions>
|
|
14
|
+
|
|
15
|
+
<categories>
|
|
16
|
+
- Added: New features, public APIs, user-facing capabilities
|
|
17
|
+
- Changed: Modified existing behavior
|
|
18
|
+
- Deprecated: Features scheduled for removal
|
|
19
|
+
- Removed: Deleted features or APIs
|
|
20
|
+
- Fixed: Bug corrections with observable impact
|
|
21
|
+
- Security: Vulnerability fixes
|
|
22
|
+
- Breaking Changes: API-incompatible modifications (use sparingly)
|
|
23
|
+
</categories>
|
|
24
|
+
|
|
25
|
+
<entry_format>
|
|
26
|
+
- Start with past-tense verb (Added, Fixed, Implemented, Updated)
|
|
27
|
+
- Describe user-visible impact, not implementation
|
|
28
|
+
- Name the specific feature, option, or behavior
|
|
29
|
+
- Keep to 1-2 lines, no trailing periods
|
|
30
|
+
</entry_format>
|
|
31
|
+
|
|
32
|
+
<examples>
|
|
33
|
+
Good:
|
|
34
|
+
- Added --dry-run flag to preview changes without applying them
|
|
35
|
+
- Fixed memory leak when processing large files
|
|
36
|
+
- Changed default timeout from 30s to 60s for slow connections
|
|
37
|
+
|
|
38
|
+
Bad:
|
|
39
|
+
- **cli**: Added dry-run flag -> scope prefix redundant
|
|
40
|
+
- Added new feature. -> vague, has trailing period
|
|
41
|
+
- Refactored parser internals -> not user-visible
|
|
42
|
+
|
|
43
|
+
Breaking Changes example:
|
|
44
|
+
- Removed legacy auth flow; users must re-authenticate with OAuth tokens
|
|
45
|
+
</examples>
|
|
46
|
+
|
|
47
|
+
<exclude>
|
|
48
|
+
Internal refactoring, code style changes, test-only modifications, minor doc updates, anything invisible to users.
|
|
49
|
+
</exclude>
|
|
50
|
+
|
|
51
|
+
<output_format>
|
|
52
|
+
Return ONLY valid JSON. No markdown fences, no explanation.
|
|
53
|
+
|
|
54
|
+
With entries: {"entries": {"Added": ["entry 1"], "Fixed": ["entry 2"]}}
|
|
55
|
+
No changelog-worthy changes: {"entries": {}}
|
|
56
|
+
</output_format>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<context>
|
|
2
|
+
Changelog: {{ changelog_path }}
|
|
3
|
+
{{#if is_package_changelog}}Scope: Package-level changelog. Omit package name prefix from entries.{{/if}}
|
|
4
|
+
</context>
|
|
5
|
+
{{#if existing_entries}}
|
|
6
|
+
|
|
7
|
+
<existing_entries>
|
|
8
|
+
Already documented—skip these:
|
|
9
|
+
{{ existing_entries }}
|
|
10
|
+
</existing_entries>
|
|
11
|
+
{{/if}}
|
|
12
|
+
|
|
13
|
+
<diff_summary>
|
|
14
|
+
{{ stat }}
|
|
15
|
+
</diff_summary>
|
|
16
|
+
|
|
17
|
+
<diff>
|
|
18
|
+
{{ diff }}
|
|
19
|
+
</diff>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<role>Expert code analyst extracting structured observations from diffs.</role>
|
|
2
|
+
|
|
3
|
+
<instructions>
|
|
4
|
+
Extract factual observations from the diff. This matters—be precise.
|
|
5
|
+
|
|
6
|
+
1. Use past-tense verb + specific target + optional purpose
|
|
7
|
+
2. Max 100 characters per observation
|
|
8
|
+
3. Consolidate related changes (e.g., "renamed 5 helper functions")
|
|
9
|
+
4. Return 1-5 observations only
|
|
10
|
+
</instructions>
|
|
11
|
+
|
|
12
|
+
<scope>
|
|
13
|
+
Include: functions, methods, types, API changes, behavior/logic changes, error handling, performance, security.
|
|
14
|
+
|
|
15
|
+
Exclude: import reordering, whitespace/formatting, comment-only changes, debug statements.
|
|
16
|
+
</scope>
|
|
17
|
+
|
|
18
|
+
<output_format>
|
|
19
|
+
Plain list, no preamble, no summary, no markdown formatting.
|
|
20
|
+
|
|
21
|
+
- added 'parse_config()' function for TOML configuration loading
|
|
22
|
+
- removed deprecated 'legacy_init()' and all callers
|
|
23
|
+
- changed 'Connection::new()' to accept '&Config' instead of individual params
|
|
24
|
+
</output_format>
|
|
25
|
+
|
|
26
|
+
Observations only. Classification happens in reduce phase.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
You are a senior engineer synthesizing file-level observations into a conventional commit analysis.
|
|
2
|
+
|
|
3
|
+
<context>
|
|
4
|
+
Given map-phase observations from analyzed files, produce a unified commit classification with changelog metadata.
|
|
5
|
+
</context>
|
|
6
|
+
|
|
7
|
+
<instructions>
|
|
8
|
+
Determine:
|
|
9
|
+
1. TYPE: Single classification for entire commit
|
|
10
|
+
2. SCOPE: Primary component (null if multi-component)
|
|
11
|
+
3. DETAILS: 3-4 summary points (max 6)
|
|
12
|
+
4. CHANGELOG: Metadata for user-visible changes
|
|
13
|
+
|
|
14
|
+
Get this right. Accuracy matters.
|
|
15
|
+
</instructions>
|
|
16
|
+
|
|
17
|
+
<scope_rules>
|
|
18
|
+
- Use component name if >=60% of changes target it
|
|
19
|
+
- Use null if spread across multiple components
|
|
20
|
+
- Use scope_candidates as primary source
|
|
21
|
+
- Valid scopes only: specific component names (api, parser, config, etc.)
|
|
22
|
+
</scope_rules>
|
|
23
|
+
|
|
24
|
+
<output_format>
|
|
25
|
+
Each detail point:
|
|
26
|
+
- Past-tense verb start (added, fixed, moved, extracted)
|
|
27
|
+
- Under 120 characters, ends with period
|
|
28
|
+
- Group related cross-file changes
|
|
29
|
+
|
|
30
|
+
Priority: user-visible behavior > performance/security > architecture > internal implementation
|
|
31
|
+
|
|
32
|
+
changelog_category: Added | Changed | Fixed | Deprecated | Removed | Security
|
|
33
|
+
user_visible: true for features, user-facing bugs, breaking changes, security fixes
|
|
34
|
+
</output_format>
|
|
35
|
+
|
|
36
|
+
<example>
|
|
37
|
+
Input observations:
|
|
38
|
+
- api/client.ts: added token refresh guard to prevent duplicate refreshes
|
|
39
|
+
- api/http.ts: introduced retry wrapper for 429 responses
|
|
40
|
+
- api/index.ts: updated exports for retry helper
|
|
41
|
+
|
|
42
|
+
Output:
|
|
43
|
+
{
|
|
44
|
+
"type": "fix",
|
|
45
|
+
"scope": "api",
|
|
46
|
+
"details": [
|
|
47
|
+
{
|
|
48
|
+
"text": "Added token refresh guard to prevent duplicate refreshes.",
|
|
49
|
+
"changelog_category": "Fixed",
|
|
50
|
+
"user_visible": true
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"text": "Introduced retry wrapper for 429 responses.",
|
|
54
|
+
"changelog_category": "Fixed",
|
|
55
|
+
"user_visible": true
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"issue_refs": []
|
|
59
|
+
}
|
|
60
|
+
</example>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{{#if types_description}}
|
|
2
|
+
<type_definitions>
|
|
3
|
+
{{ types_description }}
|
|
4
|
+
</type_definitions>
|
|
5
|
+
{{/if}}
|
|
6
|
+
|
|
7
|
+
<observations>
|
|
8
|
+
{{ observations }}
|
|
9
|
+
</observations>
|
|
10
|
+
|
|
11
|
+
<diff_statistics>
|
|
12
|
+
{{ stat }}
|
|
13
|
+
</diff_statistics>
|
|
14
|
+
|
|
15
|
+
<scope_candidates>
|
|
16
|
+
{{ scope_candidates }}
|
|
17
|
+
</scope_candidates>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
You are a commit message specialist generating precise, informative descriptions.
|
|
2
|
+
|
|
3
|
+
<context>
|
|
4
|
+
Output: ONLY the description after "{{ commit_type }}{{ scope_prefix }}:".
|
|
5
|
+
Constraint: {{ chars }} characters max, no trailing period, no type prefix in output.
|
|
6
|
+
</context>
|
|
7
|
+
|
|
8
|
+
<instructions>
|
|
9
|
+
1. Start with lowercase past-tense verb (must differ from "{{ commit_type }}")
|
|
10
|
+
2. Name the specific subsystem/component affected
|
|
11
|
+
3. Include WHY when it clarifies intent
|
|
12
|
+
4. One focused concept per message
|
|
13
|
+
|
|
14
|
+
Get this right.
|
|
15
|
+
</instructions>
|
|
16
|
+
|
|
17
|
+
<verb_reference>
|
|
18
|
+
| Type | Use instead |
|
|
19
|
+
|----------|-------------------------------------------------|
|
|
20
|
+
| feat | added, introduced, implemented, enabled |
|
|
21
|
+
| fix | corrected, resolved, patched, addressed |
|
|
22
|
+
| refactor | restructured, reorganized, migrated, simplified |
|
|
23
|
+
| perf | optimized, reduced, eliminated, accelerated |
|
|
24
|
+
| docs | documented, clarified, expanded |
|
|
25
|
+
| build | upgraded, pinned, configured |
|
|
26
|
+
| chore | cleaned, removed, renamed, organized |
|
|
27
|
+
</verb_reference>
|
|
28
|
+
|
|
29
|
+
<examples>
|
|
30
|
+
feat | TLS encryption added to HTTP client for MITM prevention
|
|
31
|
+
-> added TLS support to prevent man-in-the-middle attacks
|
|
32
|
+
|
|
33
|
+
refactor | Consolidated HTTP transport into unified builder pattern
|
|
34
|
+
-> migrated HTTP transport to unified builder API
|
|
35
|
+
|
|
36
|
+
fix | Race condition in connection pool causing exhaustion under load
|
|
37
|
+
-> corrected race condition causing connection pool exhaustion
|
|
38
|
+
|
|
39
|
+
perf | Batch processing optimized to reduce memory allocations
|
|
40
|
+
-> eliminated allocation overhead in batch processing
|
|
41
|
+
|
|
42
|
+
build | Updated serde to fix CVE-2024-1234
|
|
43
|
+
-> upgraded serde to 1.0.200 for CVE-2024-1234
|
|
44
|
+
</examples>
|
|
45
|
+
|
|
46
|
+
<banned_words>
|
|
47
|
+
comprehensive, various, several, improved, enhanced, quickly, simply, basically, this change, this commit, now
|
|
48
|
+
</banned_words>
|
|
49
|
+
|
|
50
|
+
<output_format>
|
|
51
|
+
Output the description text only. Include motivation, name specifics, stay focused.
|
|
52
|
+
</output_format>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the omp commit pipeline.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type CommitType =
|
|
6
|
+
| "feat"
|
|
7
|
+
| "fix"
|
|
8
|
+
| "refactor"
|
|
9
|
+
| "perf"
|
|
10
|
+
| "docs"
|
|
11
|
+
| "test"
|
|
12
|
+
| "build"
|
|
13
|
+
| "ci"
|
|
14
|
+
| "chore"
|
|
15
|
+
| "style"
|
|
16
|
+
| "revert";
|
|
17
|
+
|
|
18
|
+
export type ChangelogCategory =
|
|
19
|
+
| "Breaking Changes"
|
|
20
|
+
| "Added"
|
|
21
|
+
| "Changed"
|
|
22
|
+
| "Deprecated"
|
|
23
|
+
| "Removed"
|
|
24
|
+
| "Fixed"
|
|
25
|
+
| "Security";
|
|
26
|
+
|
|
27
|
+
export interface CommitCommandArgs {
|
|
28
|
+
/** Push after commit */
|
|
29
|
+
push: boolean;
|
|
30
|
+
/** Preview without committing */
|
|
31
|
+
dryRun: boolean;
|
|
32
|
+
/** Skip changelog updates */
|
|
33
|
+
noChangelog: boolean;
|
|
34
|
+
/** Use legacy deterministic pipeline */
|
|
35
|
+
legacy?: boolean;
|
|
36
|
+
/** Additional user context for the model */
|
|
37
|
+
context?: string;
|
|
38
|
+
/** Override the model selection */
|
|
39
|
+
model?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface NumstatEntry {
|
|
43
|
+
path: string;
|
|
44
|
+
additions: number;
|
|
45
|
+
deletions: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ConventionalDetail {
|
|
49
|
+
text: string;
|
|
50
|
+
changelogCategory?: ChangelogCategory;
|
|
51
|
+
userVisible: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ConventionalAnalysis {
|
|
55
|
+
type: CommitType;
|
|
56
|
+
scope: string | null;
|
|
57
|
+
details: ConventionalDetail[];
|
|
58
|
+
issueRefs: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface CommitSummary {
|
|
62
|
+
summary: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface FileObservation {
|
|
66
|
+
file: string;
|
|
67
|
+
observations: string[];
|
|
68
|
+
additions: number;
|
|
69
|
+
deletions: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface FileDiff {
|
|
73
|
+
filename: string;
|
|
74
|
+
content: string;
|
|
75
|
+
additions: number;
|
|
76
|
+
deletions: number;
|
|
77
|
+
isBinary: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface DiffHunk {
|
|
81
|
+
index: number;
|
|
82
|
+
header: string;
|
|
83
|
+
oldStart: number;
|
|
84
|
+
oldLines: number;
|
|
85
|
+
newStart: number;
|
|
86
|
+
newLines: number;
|
|
87
|
+
content: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface FileHunks {
|
|
91
|
+
filename: string;
|
|
92
|
+
isBinary: boolean;
|
|
93
|
+
hunks: DiffHunk[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ChangelogBoundary {
|
|
97
|
+
changelogPath: string;
|
|
98
|
+
files: string[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface UnreleasedSection {
|
|
102
|
+
startLine: number;
|
|
103
|
+
endLine: number;
|
|
104
|
+
entries: Record<string, string[]>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface ChangelogGenerationResult {
|
|
108
|
+
entries: Record<string, string[]>;
|
|
109
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const EXCLUDED_FILES = [
|
|
2
|
+
"Cargo.lock",
|
|
3
|
+
"package-lock.json",
|
|
4
|
+
"npm-shrinkwrap.json",
|
|
5
|
+
"yarn.lock",
|
|
6
|
+
"pnpm-lock.yaml",
|
|
7
|
+
"shrinkwrap.yaml",
|
|
8
|
+
"bun.lock",
|
|
9
|
+
"bun.lockb",
|
|
10
|
+
"deno.lock",
|
|
11
|
+
"composer.lock",
|
|
12
|
+
"Gemfile.lock",
|
|
13
|
+
"poetry.lock",
|
|
14
|
+
"Pipfile.lock",
|
|
15
|
+
"pdm.lock",
|
|
16
|
+
"uv.lock",
|
|
17
|
+
"go.sum",
|
|
18
|
+
"flake.lock",
|
|
19
|
+
"pubspec.lock",
|
|
20
|
+
"Podfile.lock",
|
|
21
|
+
"Packages.resolved",
|
|
22
|
+
"mix.lock",
|
|
23
|
+
"packages.lock.json",
|
|
24
|
+
"config.yml.lock",
|
|
25
|
+
"config.yaml.lock",
|
|
26
|
+
"settings.yml.lock",
|
|
27
|
+
"settings.yaml.lock",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const EXCLUDED_SUFFIXES = [".lock.yml", ".lock.yaml", "-lock.yml", "-lock.yaml"];
|
|
31
|
+
|
|
32
|
+
export function isExcludedFile(path: string): boolean {
|
|
33
|
+
const lower = path.toLowerCase();
|
|
34
|
+
if (EXCLUDED_FILES.some((name) => lower.endsWith(name.toLowerCase()))) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return EXCLUDED_SUFFIXES.some((suffix) => lower.endsWith(suffix));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function filterExcludedFiles<T extends { filename: string }>(files: T[]): T[] {
|
|
41
|
+
return files.filter((file) => !isExcludedFile(file.filename));
|
|
42
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, rm } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
export interface FileLockOptions {
|
|
5
|
+
staleMs?: number;
|
|
6
|
+
retries?: number;
|
|
7
|
+
retryDelayMs?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const DEFAULT_OPTIONS: Required<FileLockOptions> = {
|
|
11
|
+
staleMs: 10_000,
|
|
12
|
+
retries: 50,
|
|
13
|
+
retryDelayMs: 100,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
interface LockInfo {
|
|
17
|
+
pid: number;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getLockPath(filePath: string): string {
|
|
22
|
+
return `${filePath}.lock`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function writeLockInfo(lockPath: string): Promise<void> {
|
|
26
|
+
const info: LockInfo = { pid: process.pid, timestamp: Date.now() };
|
|
27
|
+
await Bun.write(`${lockPath}/info`, JSON.stringify(info));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function readLockInfo(lockPath: string): Promise<LockInfo | null> {
|
|
31
|
+
try {
|
|
32
|
+
const content = await readFile(`${lockPath}/info`, "utf-8");
|
|
33
|
+
return JSON.parse(content) as LockInfo;
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isProcessAlive(pid: number): boolean {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(pid, 0);
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function isLockStale(lockPath: string, staleMs: number): Promise<boolean> {
|
|
49
|
+
const info = await readLockInfo(lockPath);
|
|
50
|
+
if (!info) return true;
|
|
51
|
+
|
|
52
|
+
if (!isProcessAlive(info.pid)) return true;
|
|
53
|
+
|
|
54
|
+
if (Date.now() - info.timestamp > staleMs) return true;
|
|
55
|
+
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function tryAcquireLock(lockPath: string): Promise<boolean> {
|
|
60
|
+
try {
|
|
61
|
+
await mkdir(lockPath);
|
|
62
|
+
await writeLockInfo(lockPath);
|
|
63
|
+
return true;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if ((error as NodeJS.ErrnoException).code === "EEXIST") {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function releaseLock(lockPath: string): Promise<void> {
|
|
73
|
+
try {
|
|
74
|
+
await rm(lockPath, { recursive: true });
|
|
75
|
+
} catch {
|
|
76
|
+
// Ignore errors on release
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function acquireLock(filePath: string, options: FileLockOptions = {}): Promise<() => Promise<void>> {
|
|
81
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
82
|
+
const lockPath = getLockPath(filePath);
|
|
83
|
+
|
|
84
|
+
for (let attempt = 0; attempt < opts.retries; attempt++) {
|
|
85
|
+
if (await tryAcquireLock(lockPath)) {
|
|
86
|
+
return () => releaseLock(lockPath);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (existsSync(lockPath) && (await isLockStale(lockPath, opts.staleMs))) {
|
|
90
|
+
await releaseLock(lockPath);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await new Promise((resolve) => setTimeout(resolve, opts.retryDelayMs));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new Error(`Failed to acquire lock for ${filePath} after ${opts.retries} attempts`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function withFileLock<T>(
|
|
101
|
+
filePath: string,
|
|
102
|
+
fn: () => Promise<T>,
|
|
103
|
+
options: FileLockOptions = {},
|
|
104
|
+
): Promise<T> {
|
|
105
|
+
const release = await acquireLock(filePath, options);
|
|
106
|
+
try {
|
|
107
|
+
return await fn();
|
|
108
|
+
} finally {
|
|
109
|
+
await release();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { extname } from "node:path";
|
|
6
7
|
import {
|
|
7
8
|
type Api,
|
|
8
9
|
getGitHubCopilotBaseUrl,
|
|
@@ -15,6 +16,7 @@ import type { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage
|
|
|
15
16
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
16
17
|
import { type Static, Type } from "@sinclair/typebox";
|
|
17
18
|
import AjvModule from "ajv";
|
|
19
|
+
import { YAML } from "bun";
|
|
18
20
|
|
|
19
21
|
const Ajv = (AjvModule as any).default || AjvModule;
|
|
20
22
|
|
|
@@ -262,14 +264,21 @@ export class ModelRegistry {
|
|
|
262
264
|
});
|
|
263
265
|
}
|
|
264
266
|
|
|
265
|
-
private loadCustomModels(
|
|
266
|
-
if (!existsSync(
|
|
267
|
+
private loadCustomModels(modelsPath: string): CustomModelsResult {
|
|
268
|
+
if (!existsSync(modelsPath)) {
|
|
267
269
|
return emptyCustomModelsResult();
|
|
268
270
|
}
|
|
269
271
|
|
|
270
272
|
try {
|
|
271
|
-
const content = readFileSync(
|
|
272
|
-
const
|
|
273
|
+
const content = readFileSync(modelsPath, "utf-8");
|
|
274
|
+
const ext = extname(modelsPath).toLowerCase();
|
|
275
|
+
let config: ModelsConfig;
|
|
276
|
+
|
|
277
|
+
if (ext === ".yaml" || ext === ".yml") {
|
|
278
|
+
config = YAML.parse(content) as ModelsConfig;
|
|
279
|
+
} else {
|
|
280
|
+
config = JSON.parse(content) as ModelsConfig;
|
|
281
|
+
}
|
|
273
282
|
|
|
274
283
|
// Validate schema
|
|
275
284
|
const ajv = new Ajv();
|
|
@@ -278,7 +287,7 @@ export class ModelRegistry {
|
|
|
278
287
|
const errors =
|
|
279
288
|
validate.errors?.map((e: any) => ` - ${e.instancePath || "root"}: ${e.message}`).join("\n") ||
|
|
280
289
|
"Unknown schema error";
|
|
281
|
-
return emptyCustomModelsResult(`Invalid models
|
|
290
|
+
return emptyCustomModelsResult(`Invalid models config schema:\n${errors}\n\nFile: ${modelsPath}`);
|
|
282
291
|
}
|
|
283
292
|
|
|
284
293
|
// Additional validation
|
|
@@ -309,10 +318,10 @@ export class ModelRegistry {
|
|
|
309
318
|
return { models: this.parseModels(config), replacedProviders, overrides, error: undefined };
|
|
310
319
|
} catch (error) {
|
|
311
320
|
if (error instanceof SyntaxError) {
|
|
312
|
-
return emptyCustomModelsResult(`Failed to parse models
|
|
321
|
+
return emptyCustomModelsResult(`Failed to parse models config: ${error.message}\n\nFile: ${modelsPath}`);
|
|
313
322
|
}
|
|
314
323
|
return emptyCustomModelsResult(
|
|
315
|
-
`Failed to load models
|
|
324
|
+
`Failed to load models config: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsPath}`,
|
|
316
325
|
);
|
|
317
326
|
}
|
|
318
327
|
}
|