create-loopengine 0.1.20 → 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.20",
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,
@@ -503,6 +506,7 @@ function parseHttpToolBody(body: Record<string, unknown>): { ok: true; value: Ht
503
506
  headers: body.headers as HttpToolSpec['headers'],
504
507
  sendFieldsAsJsonBody: body.sendFieldsAsJsonBody === true,
505
508
  responseJsonPath: body.responseJsonPath as string | undefined,
509
+ safe: body.safe === true,
506
510
  },
507
511
  decision: body.decision as Decision | undefined,
508
512
  }
@@ -920,6 +924,53 @@ function handleSkillDelete(res: ServerResponse, agentName: string, skillId: stri
920
924
  res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ ok: true }))
921
925
  }
922
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
+
923
974
  // Backs the Skills tab's "Browse skillgarden catalog" section — a
924
975
  // read-only, agent-independent list of everything skillgarden ships in
925
976
  // its own bundled registry (see loopengine's own web/skillgarden-admin.ts).
@@ -2119,6 +2170,19 @@ const server = createServer(async (req, res) => {
2119
2170
  return
2120
2171
  }
2121
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
+
2122
2186
  // Backs the Skills tab's "Browse skillgarden catalog" section — see
2123
2187
  // the three handlers above it.
2124
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
  },