From a3d1dc2caefd54eb6a6453aa994d0e4bc87a9943 Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Thu, 3 Sep 2026 15:00:39 -0700 Subject: [PATCH 1/4] feat: add Pzero as an OpenAI-compatible AI provider - Register Pzero with its OpenAI-compatible API endpoint. - Disable unsupported Responses API behavior for Pzero requests. - List Pzero among supported providers in README documentation. - Add Pzero integration details to incoming changelog. --- README.md | 1 + cmd/generate_changelog/incoming/2210.txt | 5 +++++ internal/plugins/ai/openai_compatible/providers_config.go | 5 +++++ 3 files changed, 11 insertions(+) create mode 100644 cmd/generate_changelog/incoming/2210.txt diff --git a/README.md b/README.md index 117431c9d..e272973f2 100644 --- a/README.md +++ b/README.md @@ -374,6 +374,7 @@ Fabric supports a wide range of AI providers: - Mistral - Novita AI - OpenRouter +- Pzero - SiliconCloud - Synthorai - Together diff --git a/cmd/generate_changelog/incoming/2210.txt b/cmd/generate_changelog/incoming/2210.txt new file mode 100644 index 000000000..13c5a81a5 --- /dev/null +++ b/cmd/generate_changelog/incoming/2210.txt @@ -0,0 +1,5 @@ +### PR [#2210](https://github.com/danielmiessler/Fabric/pull/2210) by [ksylvan](https://github.com/ksylvan): feat: add Pzero as an OpenAI-compatible AI provider + +- Added Pzero as an OpenAI-compatible AI provider. +- Registered Pzero with its OpenAI-compatible API base URL. +- Added Pzero to the README’s list of supported AI providers. diff --git a/internal/plugins/ai/openai_compatible/providers_config.go b/internal/plugins/ai/openai_compatible/providers_config.go index d9cfafceb..13c659a55 100644 --- a/internal/plugins/ai/openai_compatible/providers_config.go +++ b/internal/plugins/ai/openai_compatible/providers_config.go @@ -289,6 +289,11 @@ var ProviderMap = map[string]ProviderConfig{ BaseURL: "https://openrouter.ai/api/v1", ImplementsResponses: false, }, + "Pzero": { + Name: "Pzero", + BaseURL: "https://api.pzero.studio/v1", + ImplementsResponses: false, + }, "SiliconCloud": { Name: "SiliconCloud", BaseURL: "https://api.siliconflow.cn/v1", From 8dce453ed78499a2c0f6a1434be8427905e4b54d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 3 Sep 2026 22:05:51 +0000 Subject: [PATCH 2/4] chore(release): Update version to v1.4.476 --- CHANGELOG.md | 8 ++++++++ cmd/fabric/version.go | 2 +- cmd/generate_changelog/changelog.db | Bin 4677632 -> 4681728 bytes cmd/generate_changelog/incoming/2210.txt | 5 ----- nix/pkgs/fabric/version.nix | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) delete mode 100644 cmd/generate_changelog/incoming/2210.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index e04993c2d..76d243016 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v1.4.476 (2026-09-03) + +### PR [#2210](https://github.com/danielmiessler/Fabric/pull/2210) by [ksylvan](https://github.com/ksylvan): feat: add Pzero as an OpenAI-compatible AI provider + +- Added Pzero as an OpenAI-compatible AI provider. +- Registered Pzero with its OpenAI-compatible API base URL. +- Added Pzero to the README’s list of supported AI providers. + ## v1.4.475 (2026-09-03) ### PR [#2209](https://github.com/danielmiessler/Fabric/pull/2209) by [kadiryildiz283](https://github.com/kadiryildiz283): feat(i18n): add Turkish (tr) translation diff --git a/cmd/fabric/version.go b/cmd/fabric/version.go index 92ca8f9b0..4d584fb1f 100644 --- a/cmd/fabric/version.go +++ b/cmd/fabric/version.go @@ -1,3 +1,3 @@ package main -var version = "v1.4.475" +var version = "v1.4.476" diff --git a/cmd/generate_changelog/changelog.db b/cmd/generate_changelog/changelog.db index 744da0d4c16c8327f2191e4e0dbe050d5cb361f8..875462dd1b6f59247f78608cf48433e7e2d02e6a 100644 GIT binary patch delta 3940 zcmcInYit}>72c=4UVHtBV>_|qGDM+&jYQ}CmT6`HGnLeeNjZB+@}5Umj9(Nw4^5|l_F5c~;IrTl;&ASwt5D$bpK z*fDMug!u8<*4#Vip7WjWd~-ejupv_8r&>xI={V}hfI}{AY{r)%?JG%4?v1j3UI1t|w4xFC8^ueaiwUJep-$LJS zFi&54yDw>;dCPCx?KtAFTiD6B>XbJu7KfdF@S^R(t!rA^Rt1lz7P`*V&J=2A%zyox z&15o-QoCZg=B)3vHCgXlZxOPPXrUvoSZsy&6btX-eAaO*=7fO22YF1=LO4WH5gZAH zIgDemkl-hw6yG0Ze{-fQ@3QTeX>0d|bEhl-E5HV@1F8Vk00*E3-~`kH>Hsc4J)i;5 z2xtPV0W<^F0$KpAfHuH7z8Y67Qj}( zw!-aKyAPZ+n+tZ-bH!|_`z8HmSI-v;PIu2ur@4oIdwY-19*Rcl?_RjSy$8?>cml8; z;05>qeE>fo00;s&KnM^9L;z7hKOhE(7w&H#aC^*r!9FtZp2bq%UikUwz>l2fi}a=O zfs1y>4QT%b&+`L-CjmPEI{~`@y8#KnQw7iS$=`Qbe`>o!tLKxV#dfEl%qK@|4fWPe z>r}uO@dDQV5WBY54 z182OaZzXHTJI{W8Ti-6nPBJRiMOi`u(Xp7-7@?xX%Q;cXAbt`{8IqMVK8k;}d2=^&Z^NmV zyn$UqIkl7Ivmc1g01h(xd3+?{mshslkhqTGBrVWPL!+l zSkk1`=W^16sJVk)PYiCQr|v&l)x65fH1UU_wG>^p*U&$HXWMsz>-ud1+qbiGpZ&gCURIkF38i83*=FpzCVp^bQhDj_fAhkX;>RK^|r1lzmt(& zPIqy0;BpL=wj}-%*h=Rw$82>9n{S_{=LJ!wuixq6=$lt!9aSJ8pqBpZA?J2hJ!FW7bl7s^n8yIO-8@VdipJlr#i+Ys|YqGKOg}L&8%qO)O3NXKSF9{^0fAw)N1q zlHw3H6l&xPn=0*gJO%mypOEubj!E`}(jV`j+$0#9Mro(EXfe13k88 zu)ejNu4XI^mZVHS?(ul$rYDI6)Uh!)dTeYNmULAX^1PvWloLzlpds*?luGb%!xc(x zD*8szBiIQp=ZMTm5OEfXng({nQl28Jn4V>xlFbXm(3Telac0RqHq_o-|I5qX{GNV%==Cm+7bcxhRH(2w)aQdk-i?N(_5>dZ1;% zDV9fFLzP2Pv&Oz<)@U$e9EEt$X0bx8k}&3ZqOkPzNmb5gCXLt03hum1gK5}$Aw&2I3!E7sn*@xHZ5keB~^j@S0r@#W^Wrk@|)WyOJD?hf5n2@qB?zkOJlfF7~Y5sajaz-;uuIH!Q(vXio} z4Ww^ap{RwRsmxh*a7L^`Lts3-@U2j?gndJ_vQ~|dM~aPC>5lh%x;CsT)>1ii-}eUE zy0Na4oB~5=_=mybBVRou=xAPI&Vr0No`WILK`^2YS%FuVq$bIbM+O+yjGWjvQihRK zD9h|WVeA)2i+$5Yrj+F!SuR0V8kiiY$g9g< z__eG7$F z%#nWhCnyz7@zJpt-JktT!X0-%?p@Tq-MtUmfHQ=?{bs0!PJCQtTX`+)JSH8J9^-2C zoR4k$-|j{%!lzx1*!t2fVwnYe`t69G*!lGE=a&6n3w4h`izQui$H&}$e>xn&(FpOU mVrd~23*b};6HJ295FbtRu~0M^2=_+?_xP8_SM-QoSpN+=1uS;} delta 798 zcmbu(Pe_wt90&0CectEYJKuMkt(;~yeRY}6rhDh>{IivRT54F)3cU=}N+wiN!=>3D zY?v~F5QoH*fmo3pxf-gw1g^yfvK_i4`uFx;6KhQ`pbNAZ2px$B95;ZwB6cg)yUt^tG2{5!ZvQuAFE5r zVQRUmkH$yhx3vkbO^CmKQ%8+(ipdGGq*AB!Ra%V);_*y}i$xz1%GVNP$W8@8@Uzy7 z#9$&TtV+*J5|Ds`3>Hwp3VEP{1~#yR1M*=9IAJI3f&y?sAr!%GD26>y0(-#?rF>?x z>}F1pW5NmHoxs$n{=nw=mj76prI&5JVsv|ORG+6*5i!`GCDn>}x3o^`m)P8Tu$pK4 z^y5AMS(45!>rf6A;DLQm3HzanXP2u_UKa%}>)r*CJuLTLAa;qX72YSR*u2u;uoEfC^czHqTeJjdl|c#RON#NVF|zgEQs zHrpSbla*V-{m!&!APfiL5VS%Yv_l6R=AMDbmvU*H=9rR-oadvdNR%?;BXOp4(-Anr zbJLyXC&^>U+*8zU?rhg07M>aIO5SnE)GcUJs$?yaP3q>(l&n$i{@L~Ym_t@$g1yQ% Up}p1e)L7P8a8%{7p6;ivKS#?8=l}o! diff --git a/cmd/generate_changelog/incoming/2210.txt b/cmd/generate_changelog/incoming/2210.txt deleted file mode 100644 index 13c5a81a5..000000000 --- a/cmd/generate_changelog/incoming/2210.txt +++ /dev/null @@ -1,5 +0,0 @@ -### PR [#2210](https://github.com/danielmiessler/Fabric/pull/2210) by [ksylvan](https://github.com/ksylvan): feat: add Pzero as an OpenAI-compatible AI provider - -- Added Pzero as an OpenAI-compatible AI provider. -- Registered Pzero with its OpenAI-compatible API base URL. -- Added Pzero to the README’s list of supported AI providers. diff --git a/nix/pkgs/fabric/version.nix b/nix/pkgs/fabric/version.nix index a94204779..794426ec0 100644 --- a/nix/pkgs/fabric/version.nix +++ b/nix/pkgs/fabric/version.nix @@ -1 +1 @@ -"1.4.475" +"1.4.476" From f141b68f125ce0c6d5ff413109cc8848a12b8be0 Mon Sep 17 00:00:00 2001 From: Kayvan Sylvan Date: Thu, 3 Sep 2026 15:28:35 -0700 Subject: [PATCH 3/4] fix: prevent pattern loader temporary directory leaks - Create pattern temporary directories only during database population. - Remove temporary directories after successful or failed downloads. - Add regression tests for lazy creation and cleanup. - Document pattern loader cleanup behavior in changelog. --- cmd/generate_changelog/incoming/2211.txt | 4 ++ internal/tools/patterns_loader.go | 16 +++--- internal/tools/patterns_loader_test.go | 63 ++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 cmd/generate_changelog/incoming/2211.txt create mode 100644 internal/tools/patterns_loader_test.go diff --git a/cmd/generate_changelog/incoming/2211.txt b/cmd/generate_changelog/incoming/2211.txt new file mode 100644 index 000000000..72498b92f --- /dev/null +++ b/cmd/generate_changelog/incoming/2211.txt @@ -0,0 +1,4 @@ +### PR [#2211](https://github.com/danielmiessler/Fabric/pull/2211) by [ksylvan](https://github.com/ksylvan): fix: prevent pattern loader temporary directory leaks + +- Prevent pattern loader leaks by lazily creating temporary directories during database population and cleaning them up after successful or failed downloads. +- Add regression tests for lazy directory creation and cleanup. diff --git a/internal/tools/patterns_loader.go b/internal/tools/patterns_loader.go index 8351a2d82..103356bfc 100644 --- a/internal/tools/patterns_loader.go +++ b/internal/tools/patterns_loader.go @@ -59,13 +59,6 @@ type PatternsLoader struct { func (o *PatternsLoader) configure() (err error) { o.pathPatternsPrefix = fmt.Sprintf("%v/", o.DefaultFolder.Value) - // Use a consistent temp folder name regardless of the source path structure - tempDir, err := os.MkdirTemp("", "fabric-patterns-") - if err != nil { - return fmt.Errorf(i18n.T("patterns_failed_create_temp_folder"), err) - } - o.tempPatternsFolder = tempDir - return } @@ -96,6 +89,15 @@ func (o *PatternsLoader) PopulateDB() (err error) { fmt.Println() fmt.Println() + // Create the temp folder here, not in configure(), so invocations that + // do not download patterns do not leak an empty directory (issue #2190). + var tempDir string + if tempDir, err = os.MkdirTemp("", "fabric-patterns-"); err != nil { + return fmt.Errorf(i18n.T("patterns_failed_create_temp_folder"), err) + } + o.tempPatternsFolder = tempDir + defer os.RemoveAll(tempDir) + originalPath := o.DefaultFolder.Value if err = o.gitCloneAndCopy(); err != nil { return fmt.Errorf(i18n.T("patterns_failed_download_from_git"), err) diff --git a/internal/tools/patterns_loader_test.go b/internal/tools/patterns_loader_test.go new file mode 100644 index 000000000..eb62e45b5 --- /dev/null +++ b/internal/tools/patterns_loader_test.go @@ -0,0 +1,63 @@ +package tools + +import ( + "os" + "path/filepath" + "testing" + + "github.com/danielmiessler/fabric/internal/plugins/db/fsdb" +) + +// Configure runs on every fabric invocation via the plugin registry. It must +// not create the patterns temp directory; only PopulateDB uses it. +func TestConfigureDoesNotCreateTempDir(t *testing.T) { + tmp := t.TempDir() + t.Setenv("TMPDIR", tmp) + t.Setenv("TMP", tmp) + t.Setenv("TEMP", tmp) + + loader := NewPatternsLoader(&fsdb.PatternsEntity{ + StorageEntity: &fsdb.StorageEntity{Dir: t.TempDir()}, + }) + if err := loader.Configure(); err != nil { + t.Fatalf("Configure() failed: %v", err) + } + + matches, err := filepath.Glob(filepath.Join(tmp, "fabric-patterns-*")) + if err != nil { + t.Fatal(err) + } + if len(matches) != 0 { + t.Errorf("Configure() created temp directories: %v", matches) + } +} + +// PopulateDB must create the temp directory lazily and remove it when done, +// even on failure. +func TestPopulateDBCleansUpTempDir(t *testing.T) { + tmp := t.TempDir() + t.Setenv("TMPDIR", tmp) + t.Setenv("TMP", tmp) + t.Setenv("TEMP", tmp) + + loader := NewPatternsLoader(&fsdb.PatternsEntity{ + StorageEntity: &fsdb.StorageEntity{Dir: t.TempDir()}, + }) + if err := loader.Configure(); err != nil { + t.Fatalf("Configure() failed: %v", err) + } + // Point at an invalid repo so PopulateDB fails fast without network. + loader.DefaultGitRepoUrl.Value = filepath.Join(t.TempDir(), "no-such-repo") + + if err := loader.PopulateDB(); err == nil { + t.Fatal("PopulateDB() unexpectedly succeeded with invalid repo") + } + + entries, err := os.ReadDir(tmp) + if err != nil { + t.Fatal(err) + } + for _, e := range entries { + t.Errorf("PopulateDB() left temp entry behind: %v", e.Name()) + } +} From 6b0914d1bb0dbf54facec1743838c7312e945634 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 3 Sep 2026 22:45:25 +0000 Subject: [PATCH 4/4] chore(release): Update version to v1.4.477 --- CHANGELOG.md | 7 +++++++ cmd/fabric/version.go | 2 +- cmd/generate_changelog/changelog.db | Bin 4681728 -> 4689920 bytes cmd/generate_changelog/incoming/2211.txt | 4 ---- nix/pkgs/fabric/version.nix | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 cmd/generate_changelog/incoming/2211.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d243016..f8be3a4f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v1.4.477 (2026-09-03) + +### PR [#2211](https://github.com/danielmiessler/Fabric/pull/2211) by [ksylvan](https://github.com/ksylvan): fix: prevent pattern loader temporary directory leaks + +- Prevent pattern loader leaks by lazily creating temporary directories during database population and cleaning them up after successful or failed downloads. +- Add regression tests for lazy directory creation and cleanup. + ## v1.4.476 (2026-09-03) ### PR [#2210](https://github.com/danielmiessler/Fabric/pull/2210) by [ksylvan](https://github.com/ksylvan): feat: add Pzero as an OpenAI-compatible AI provider diff --git a/cmd/fabric/version.go b/cmd/fabric/version.go index 4d584fb1f..2d883c1ff 100644 --- a/cmd/fabric/version.go +++ b/cmd/fabric/version.go @@ -1,3 +1,3 @@ package main -var version = "v1.4.476" +var version = "v1.4.477" diff --git a/cmd/generate_changelog/changelog.db b/cmd/generate_changelog/changelog.db index 875462dd1b6f59247f78608cf48433e7e2d02e6a..fd6ae8a44b8c7684a2d7be818bada9b0dbb5970a 100644 GIT binary patch delta 5870 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