🔥 Sync 2026-09-05 21:18:46

This commit is contained in:
github-actions[bot] committed 2026-09-05 21:18:46 +08:00
1 parent e88d0b9fed
commit b05ff8a1b6
45 files changed
+506 -272

No files matched your search

+15 -2
View File
@@ -15,7 +15,7 @@ AGENTFLOW_HASH_aarch64:=6d733ebc49b095bf8670a1b655a13bb8ad98c90ced19701b67d5cdd4
PKG_NAME:=agentflow
PKG_VERSION:=0.3.0
PKG_RELEASE:=6
PKG_RELEASE:=7
AGENTFLOW_URL_FILE:=agentflow-linux-$(AGENTFLOW_ARCH)
AGENTFLOW_DOWNLOAD:=$(AGENTFLOW_URL_FILE)-$(AGENTFLOW_HASH_$(ARCH))
@@ -52,6 +52,16 @@ define Package/$(PKG_NAME)/conffiles
/etc/config/agentflow
endef
define Package/$(PKG_NAME)/prerm
#!/bin/sh
if [ "$${IPKG_INSTROOT}" = "" ]; then
if [ "$$(readlink /usr/share/linkeasefull/desktop-apps.d/30-agentflow.json 2>/dev/null)" = "/usr/share/agentflow/agentflow-plugin.json" ]; then
rm -f /usr/share/linkeasefull/desktop-apps.d/30-agentflow.json
fi
fi
exit 0
endef
define Build/Prepare
$(INSTALL_DIR) $(PKG_BUILD_DIR)
$(CP) $(DL_DIR)/$(AGENTFLOW_DOWNLOAD) $(PKG_BUILD_DIR)/agentflow
@@ -64,11 +74,14 @@ define Build/Compile
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/uci-defaults $(1)/etc/config
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/uci-defaults $(1)/etc/config $(1)/usr/share/agentflow/www $(1)/usr/share/linkeasefull/desktop-apps.d
$(INSTALL_BIN) $(PKG_BUILD_DIR)/agentflow $(1)/usr/sbin/agentflow
$(INSTALL_BIN) ./files/agentflow.init $(1)/etc/init.d/agentflow
$(INSTALL_BIN) ./files/agentflow.uci-default $(1)/etc/uci-defaults/09-agentflow
$(INSTALL_CONF) ./files/agentflow.config $(1)/etc/config/agentflow
$(INSTALL_DATA) ./files/agentflow-plugin.json $(1)/usr/share/agentflow/agentflow-plugin.json
$(INSTALL_DATA) ./files/www/logo.svg $(1)/usr/share/agentflow/www/logo.svg
ln -sf /usr/share/agentflow/agentflow-plugin.json $(1)/usr/share/linkeasefull/desktop-apps.d/30-agentflow.json
endef
$(eval $(call Download,agentflow))
+41
View File
@@ -0,0 +1,41 @@
{
"schemaVersion": 1,
"id": "agentflow",
"name": "AgentFlow",
"icon": "logo.svg",
"staticRoot": "/usr/share/agentflow/www",
"desktop": {
"mode": "module",
"entry": "desktop-entry.js",
"isolation": "shadow-dom"
},
"standalone": {
"entry": "index.html",
"basePath": "/apps/agentflow/",
"url": "/cgi-bin/luci/admin/services/agentflow/open",
"externalOpen": {
"enabled": true,
"label": "Open AgentFlow"
}
},
"auth": {
"mode": "passthrough"
},
"backend": {
"type": "http",
"scheme": "http",
"host": "127.0.0.1",
"portFromUci": "agentflow.@agentflow[0].port",
"defaultPort": 9000,
"upstreamBasePath": "/apps/agentflow/",
"pathMode": "preserve",
"proxyMode": "app-base"
},
"window": {
"width": 1180,
"height": 760,
"singleton": true
},
"capabilities": ["agent", "coding", "workflow"],
"categories": ["development", "ai"]
}
+21
View File
@@ -0,0 +1,21 @@
<svg
width="150"
height="150"
viewBox="0 0 150 150"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="150" height="150" rx="30" fill="#f5f1e8" />
<text
x="50%"
y="54%"
text-anchor="middle"
dominant-baseline="middle"
font-size="68"
font-weight="700"
font-family="Georgia, 'Times New Roman', serif"
letter-spacing="-4"
fill="#111111"
>
AF
</text>
</svg>

After

Width:  |  Height:  |  Size: 408 B

@@ -0,0 +1,48 @@
import json
import pathlib
import unittest
APP_DIR = pathlib.Path(__file__).resolve().parents[1]
class DesktopManifestContractTest(unittest.TestCase):
def setUp(self):
self.manifest = json.loads(
(APP_DIR / "files" / "agentflow-plugin.json").read_text()
)
def test_manifest_uses_agentflow_app_base_proxy(self):
self.assertEqual(self.manifest["id"], "agentflow")
self.assertEqual(self.manifest["staticRoot"], "/usr/share/agentflow/www")
self.assertEqual(self.manifest["standalone"]["entry"], "index.html")
self.assertEqual(self.manifest["standalone"]["basePath"], "/apps/agentflow/")
self.assertEqual(
self.manifest["standalone"]["url"],
"/cgi-bin/luci/admin/services/agentflow/open",
)
self.assertEqual(
self.manifest["standalone"]["externalOpen"],
{"enabled": True, "label": "Open AgentFlow"},
)
self.assertEqual(self.manifest["auth"]["mode"], "passthrough")
backend = self.manifest["backend"]
self.assertEqual(backend["upstreamBasePath"], "/apps/agentflow/")
self.assertEqual(backend["pathMode"], "preserve")
self.assertEqual(backend["proxyMode"], "app-base")
def test_desktop_entry_matches_manifest_contract(self):
desktop = self.manifest["desktop"]
self.assertEqual(desktop["mode"], "module")
self.assertEqual(desktop["entry"], "desktop-entry.js")
self.assertEqual(desktop["isolation"], "shadow-dom")
self.assertFalse(
(APP_DIR / "files" / "www" / "desktop-entry.js").exists(),
"desktop-entry.js must be served by AgentFlow backend, not the static iframe wrapper",
)
if __name__ == "__main__":
unittest.main()
+18 -3
View File
@@ -2,12 +2,27 @@ from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parents[3]
APPLICATIONS = ROOT / "applications"
THIS_FILE = Path(__file__).resolve()
def read(relative):
return (APPLICATIONS / relative).read_text()
relative_path = Path(relative)
package = relative_path.parts[0]
app = package[9:] if package.startswith("luci-app-") else package
remainder = Path(*relative_path.parts[1:])
candidates = [
THIS_FILE.parents[index] / relative_path
for index in range(2, min(len(THIS_FILE.parents), 6))
]
candidates.append(THIS_FILE.parents[3] / app / package / remainder)
for candidate in candidates:
if candidate.exists():
return candidate.read_text()
searched = "\n".join(str(candidate) for candidate in candidates)
raise FileNotFoundError(f"{relative} not found; searched:\n{searched}")
class MiseRuntimeContractTest(unittest.TestCase):