create-loopengine 0.1.21 → 0.1.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-loopengine",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Scaffold a new loopengine agent project — a runnable HTTP server with one example agent, in your own repo.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -85,6 +85,9 @@ import {
85
85
  deleteSkill,
86
86
  SkillInvalidIdError,
87
87
  SkillNotFoundError,
88
+ listDeclaredEnvVars,
89
+ setEnvVar,
90
+ EnvVarNameError,
88
91
  listSkillgardenCatalog,
89
92
  readSkillgardenCatalogEntry,
90
93
  addSkillgardenSkillToAgent,
@@ -921,6 +924,53 @@ function handleSkillDelete(res: ServerResponse, agentName: string, skillId: stri
921
924
  res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ ok: true }))
922
925
  }
923
926
 
927
+ // Backs the Admin UI's "Environment" section — every env var a package
928
+ // (see loopengine's own PACKAGES.md, bin/package-manager.ts) declared it
929
+ // needs for this agent, with set/not-set status only. Read-only, so no
930
+ // extra auth gate beyond the normal Basic Auth middleware every admin
931
+ // route already has.
932
+ function handleEnvGet(res: ServerResponse, agentName: string): void {
933
+ if (!getEntry(agentName)) {
934
+ res.writeHead(404, { 'content-type': 'application/json' }).end(JSON.stringify({ error: `unknown agent '${agentName}'` }))
935
+ return
936
+ }
937
+ res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(listDeclaredEnvVars(agentName)))
938
+ }
939
+
940
+ // Writes a raw secret value into .env — meaningfully more sensitive than
941
+ // the rest of the admin surface (config/business data vs. an actual
942
+ // credential), so unlike every other route here, this one refuses
943
+ // outright when LOOPENGINE_ADMIN_AUTH isn't set at all, rather than just
944
+ // warning at startup and proceeding open like the rest of this file does
945
+ // (see loopengine's own PACKAGES.md, "Managing package secrets in the
946
+ // Admin UI" — LOOPENGINE_ADMIN_AUTH being optional today is an
947
+ // acceptable gap for config, not for secrets).
948
+ async function handleEnvPut(req: IncomingMessage, res: ServerResponse, agentName: string, varName: string): Promise<void> {
949
+ if (!adminAuth) {
950
+ res.writeHead(403, { 'content-type': 'application/json' }).end(
951
+ JSON.stringify({ error: 'Refusing to set an env var without LOOPENGINE_ADMIN_AUTH configured — set it before managing secrets through this route.' }),
952
+ )
953
+ return
954
+ }
955
+ if (!getEntry(agentName)) {
956
+ res.writeHead(404, { 'content-type': 'application/json' }).end(JSON.stringify({ error: `unknown agent '${agentName}'` }))
957
+ return
958
+ }
959
+ const body = await readJsonBody(req)
960
+ if (typeof body.value !== 'string') {
961
+ res.writeHead(400, { 'content-type': 'application/json' }).end(JSON.stringify({ error: 'value is required' }))
962
+ return
963
+ }
964
+ try {
965
+ setEnvVar(varName, body.value)
966
+ } catch (err) {
967
+ const status = err instanceof EnvVarNameError ? 400 : 500
968
+ res.writeHead(status, { 'content-type': 'application/json' }).end(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }))
969
+ return
970
+ }
971
+ res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ ok: true }))
972
+ }
973
+
924
974
  // Backs the Skills tab's "Browse skillgarden catalog" section — a
925
975
  // read-only, agent-independent list of everything skillgarden ships in
926
976
  // its own bundled registry (see loopengine's own web/skillgarden-admin.ts).
@@ -2120,6 +2170,19 @@ const server = createServer(async (req, res) => {
2120
2170
  return
2121
2171
  }
2122
2172
 
2173
+ // Backs the Admin UI's "Environment" section — see
2174
+ // handleEnvGet/handleEnvPut's own doc comments above.
2175
+ const envListMatch = pathname.match(/^\/agents\/([^/]+)\/env$/)
2176
+ if (envListMatch && req.method === 'GET') {
2177
+ handleEnvGet(res, decodeURIComponent(envListMatch[1]))
2178
+ return
2179
+ }
2180
+ const envVarMatch = pathname.match(/^\/agents\/([^/]+)\/env\/([^/]+)$/)
2181
+ if (envVarMatch && req.method === 'PUT') {
2182
+ await handleEnvPut(req, res, decodeURIComponent(envVarMatch[1]), decodeURIComponent(envVarMatch[2]))
2183
+ return
2184
+ }
2185
+
2123
2186
  // Backs the Skills tab's "Browse skillgarden catalog" section — see
2124
2187
  // the three handlers above it.
2125
2188
  if (req.method === 'GET' && pathname === '/skillgarden-catalog') {
@@ -9,7 +9,7 @@
9
9
  "cli": "tsx adapters/cli.ts"
10
10
  },
11
11
  "dependencies": {
12
- "loopengine": "^0.1.10",
12
+ "loopengine": "^0.1.11",
13
13
  "actauth": "^0.0.12",
14
14
  "skillgarden": "^0.0.9"
15
15
  },