create-loopengine 0.1.33 → 0.1.35

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.33",
3
+ "version": "0.1.35",
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",
@@ -868,7 +868,18 @@ async function handleEditAgent(req: IncomingMessage, res: ServerResponse, agentN
868
868
  }
869
869
  updateAgent(agentName, { config: configPatch, createModelCall })
870
870
 
871
- res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(await describeAgent(getEntry(agentName)!)))
871
+ // Same "compute before writeHead" reasoning as the GET .../config
872
+ // route above — describeAgent can throw (a broken tools/index.ts
873
+ // import), and chaining it straight into .end()'s argument would send
874
+ // a 200 status before finding that out.
875
+ let described: Record<string, unknown>
876
+ try {
877
+ described = await describeAgent(getEntry(agentName)!)
878
+ } catch (err) {
879
+ res.writeHead(500, { 'content-type': 'application/json' }).end(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }))
880
+ return
881
+ }
882
+ res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(described))
872
883
  }
873
884
 
874
885
  // Backs the Skills tab's edit form (GET .../skills/:skillId to populate
@@ -964,6 +975,17 @@ async function handleEnvPut(req: IncomingMessage, res: ServerResponse, agentName
964
975
  res.writeHead(400, { 'content-type': 'application/json' }).end(JSON.stringify({ error: 'value is required' }))
965
976
  return
966
977
  }
978
+ // A dropdown-backed var (AbilityEnvDecl.options) is still writable
979
+ // through this same raw route — worth rejecting an out-of-set value
980
+ // here too, not just skipping validation because the Admin UI's own
981
+ // <select> would never have produced one.
982
+ const declared = listDeclaredEnvVars(agentName).find((v) => v.name === varName)
983
+ if (declared?.options && !declared.options.includes(body.value)) {
984
+ res.writeHead(400, { 'content-type': 'application/json' }).end(
985
+ JSON.stringify({ error: `"${body.value}" isn't one of this var's allowed values: ${declared.options.join(', ')}` }),
986
+ )
987
+ return
988
+ }
967
989
  try {
968
990
  setEnvVar(varName, body.value)
969
991
  } catch (err) {
@@ -2087,7 +2109,23 @@ const server = createServer(async (req, res) => {
2087
2109
  res.writeHead(404, { 'content-type': 'application/json' }).end(JSON.stringify({ error: `unknown agent '${agentName}'` }))
2088
2110
  return
2089
2111
  }
2090
- res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(await describeAgent(entry)))
2112
+ // describeAgent dynamically imports this agent's own tools/index.ts
2113
+ // (loadDefaultTools) — a broken import there (a bad tool file, a
2114
+ // dependency the agent's own code needs but doesn't have) throws.
2115
+ // Computed before writeHead, not chained directly into .end() as an
2116
+ // argument — chaining would send the 200 status line first, then
2117
+ // throw while still computing the body, leaving the connection
2118
+ // open with headers sent but no body ever written (a client-side
2119
+ // "Unexpected end of JSON input", not a clear error) instead of a
2120
+ // real 500 with an actual message.
2121
+ let described: Record<string, unknown>
2122
+ try {
2123
+ described = await describeAgent(entry)
2124
+ } catch (err) {
2125
+ res.writeHead(500, { 'content-type': 'application/json' }).end(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }))
2126
+ return
2127
+ }
2128
+ res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(described))
2091
2129
  return
2092
2130
  }
2093
2131