agency-lang 0.1.0 → 0.1.1

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.
Files changed (143) hide show
  1. package/dist/lib/backends/agencyGenerator.d.ts +1 -2
  2. package/dist/lib/backends/agencyGenerator.js +4 -13
  3. package/dist/lib/backends/typescriptBuilder.js +8 -1
  4. package/dist/lib/cli/commands.js +1 -1
  5. package/dist/lib/cli/debug.js +1 -1
  6. package/dist/lib/cli/schedule/backends/launchd.js +2 -0
  7. package/dist/lib/cli/schedule/test.d.ts +14 -0
  8. package/dist/lib/cli/schedule/test.js +29 -0
  9. package/dist/lib/cli/serve.d.ts +8 -0
  10. package/dist/lib/cli/serve.js +85 -0
  11. package/dist/lib/config.d.ts +11 -3
  12. package/dist/lib/config.js +1 -0
  13. package/dist/lib/debugger/overlays.d.ts +1 -1
  14. package/dist/lib/debugger/overlays.js +1 -1
  15. package/dist/lib/debugger/testSession.d.ts +1 -1
  16. package/dist/lib/debugger/testSession.js +1 -1
  17. package/dist/lib/debugger/ui.d.ts +1 -1
  18. package/dist/lib/debugger/ui.js +1 -1
  19. package/dist/lib/logger.d.ts +8 -0
  20. package/dist/lib/logger.js +21 -0
  21. package/dist/lib/logger.test.d.ts +1 -0
  22. package/dist/lib/logger.test.js +44 -0
  23. package/dist/lib/lsp/semantics.js +2 -0
  24. package/dist/lib/parser.js +2 -2
  25. package/dist/lib/parsers/assignment.test.js +9 -9
  26. package/dist/lib/parsers/exportConst.test.d.ts +1 -0
  27. package/dist/lib/parsers/exportConst.test.js +41 -0
  28. package/dist/lib/parsers/exportNode.test.d.ts +1 -0
  29. package/dist/lib/parsers/exportNode.test.js +37 -0
  30. package/dist/lib/parsers/parsers.d.ts +1 -1
  31. package/dist/lib/parsers/parsers.js +81 -21
  32. package/dist/lib/runtime/agencyFunction.d.ts +4 -0
  33. package/dist/lib/runtime/agencyFunction.js +8 -0
  34. package/dist/lib/serve/constants.d.ts +1 -0
  35. package/dist/lib/serve/constants.js +1 -0
  36. package/dist/lib/serve/discovery.d.ts +9 -0
  37. package/dist/lib/serve/discovery.js +35 -0
  38. package/dist/lib/serve/discovery.test.d.ts +1 -0
  39. package/dist/lib/serve/discovery.test.js +105 -0
  40. package/dist/lib/serve/http/adapter.d.ts +18 -0
  41. package/dist/lib/serve/http/adapter.js +150 -0
  42. package/dist/lib/serve/http/adapter.test.d.ts +1 -0
  43. package/dist/lib/serve/http/adapter.test.js +121 -0
  44. package/dist/lib/serve/http/auth.d.ts +1 -0
  45. package/dist/lib/serve/http/auth.js +10 -0
  46. package/dist/lib/serve/http/auth.test.d.ts +1 -0
  47. package/dist/lib/serve/http/auth.test.js +22 -0
  48. package/dist/lib/serve/mcp/adapter.d.ts +18 -0
  49. package/dist/lib/serve/mcp/adapter.js +111 -0
  50. package/dist/lib/serve/mcp/adapter.test.d.ts +1 -0
  51. package/dist/lib/serve/mcp/adapter.test.js +107 -0
  52. package/dist/lib/serve/types.d.ts +16 -0
  53. package/dist/lib/serve/types.js +1 -0
  54. package/dist/lib/serve/util.d.ts +6 -0
  55. package/dist/lib/serve/util.js +36 -0
  56. package/dist/lib/symbolTable.d.ts +8 -1
  57. package/dist/lib/symbolTable.js +11 -0
  58. package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +1 -1
  59. package/dist/lib/templates/backends/typescriptGenerator/imports.js +1 -1
  60. package/dist/lib/templates/cli/schedule/plist.d.ts +3 -1
  61. package/dist/lib/templates/cli/schedule/plist.js +7 -0
  62. package/dist/lib/tui/builders.d.ts +7 -0
  63. package/dist/lib/tui/builders.js +58 -0
  64. package/dist/lib/tui/colors.d.ts +3 -0
  65. package/dist/lib/tui/colors.js +24 -0
  66. package/dist/lib/tui/elements.d.ts +61 -0
  67. package/dist/lib/tui/elements.js +1 -0
  68. package/dist/lib/tui/frame.d.ts +27 -0
  69. package/dist/lib/tui/frame.js +42 -0
  70. package/dist/lib/tui/index.d.ts +18 -0
  71. package/dist/lib/tui/index.js +18 -0
  72. package/dist/lib/tui/input/scripted.d.ts +12 -0
  73. package/dist/lib/tui/input/scripted.js +46 -0
  74. package/dist/lib/tui/input/terminal.d.ts +14 -0
  75. package/dist/lib/tui/input/terminal.js +131 -0
  76. package/dist/lib/tui/input/types.d.ts +10 -0
  77. package/dist/lib/tui/input/types.js +1 -0
  78. package/dist/lib/tui/layout.d.ts +6 -0
  79. package/dist/lib/tui/layout.js +191 -0
  80. package/dist/lib/tui/output/recorder.d.ts +14 -0
  81. package/dist/lib/tui/output/recorder.js +64 -0
  82. package/dist/lib/tui/output/terminal.d.ts +16 -0
  83. package/dist/lib/tui/output/terminal.js +63 -0
  84. package/dist/lib/tui/output/types.d.ts +5 -0
  85. package/dist/lib/tui/output/types.js +1 -0
  86. package/dist/lib/tui/render/ansi.d.ts +2 -0
  87. package/dist/lib/tui/render/ansi.js +43 -0
  88. package/dist/lib/tui/render/flatten.d.ts +9 -0
  89. package/dist/lib/tui/render/flatten.js +32 -0
  90. package/dist/lib/tui/render/html.d.ts +2 -0
  91. package/dist/lib/tui/render/html.js +45 -0
  92. package/dist/lib/tui/render/plaintext.d.ts +2 -0
  93. package/dist/lib/tui/render/plaintext.js +7 -0
  94. package/dist/lib/tui/render/renderer.d.ts +3 -0
  95. package/dist/lib/tui/render/renderer.js +189 -0
  96. package/dist/lib/tui/screen.d.ts +24 -0
  97. package/dist/lib/tui/screen.js +34 -0
  98. package/dist/lib/tui/styleParser.d.ts +8 -0
  99. package/dist/lib/tui/styleParser.js +86 -0
  100. package/dist/lib/tui/utils.d.ts +15 -0
  101. package/dist/lib/tui/utils.js +18 -0
  102. package/dist/lib/typeChecker/scopes.js +6 -0
  103. package/dist/lib/typeChecker.test.js +53 -0
  104. package/dist/lib/types/graphNode.d.ts +1 -2
  105. package/dist/lib/types.d.ts +1 -0
  106. package/dist/scripts/agency.js +55 -0
  107. package/package.json +28 -29
  108. package/stdlib/agent.js +10 -3
  109. package/stdlib/array.js +40 -13
  110. package/stdlib/browser.js +4 -1
  111. package/stdlib/calendar.js +19 -6
  112. package/stdlib/clipboard.js +7 -2
  113. package/stdlib/date.js +46 -15
  114. package/stdlib/email.js +10 -3
  115. package/stdlib/fs.js +22 -7
  116. package/stdlib/http.js +4 -1
  117. package/stdlib/imessage.js +4 -1
  118. package/stdlib/index.js +52 -17
  119. package/stdlib/keyring.js +13 -4
  120. package/stdlib/lib/speech.js +60 -1
  121. package/stdlib/math.js +13 -4
  122. package/stdlib/oauth.js +13 -4
  123. package/stdlib/object.js +16 -5
  124. package/stdlib/path.js +22 -7
  125. package/stdlib/policy.js +7 -2
  126. package/stdlib/shell.agency +64 -19
  127. package/stdlib/shell.js +28 -15
  128. package/stdlib/sms.js +4 -1
  129. package/stdlib/speech.agency +19 -1
  130. package/stdlib/speech.js +163 -3
  131. package/stdlib/strategy.js +16 -5
  132. package/stdlib/system.js +19 -6
  133. package/stdlib/ui.js +40 -13
  134. package/stdlib/weather.js +10 -3
  135. package/stdlib/wikipedia.js +10 -3
  136. package/dist/lib/agents/agency-agent/run.js +0 -113
  137. package/dist/lib/agents/agency-agent/subagents/code.js +0 -628
  138. package/dist/lib/agents/agency-agent/subagents/plan.js +0 -445
  139. package/dist/lib/agents/agency-agent/subagents/task.js +0 -557
  140. package/scripts/hooks/postinstall.js +0 -13
  141. package/stdlib/_builtins.js +0 -134
  142. package/stdlib/_math.js +0 -9
  143. package/stdlib/lib/process.js +0 -29
@@ -3,7 +3,7 @@ import { AccessChainElement, ValueAccess } from "../types/access.js";
3
3
  import { BlockArgument } from "../types/blockArgument.js";
4
4
  import { AgencyArray, AgencyObject } from "../types/dataStructures.js";
5
5
  import { FunctionCall, FunctionDefinition } from "../types/function.js";
6
- import { GraphNodeDefinition, Visibility } from "../types/graphNode.js";
6
+ import { GraphNodeDefinition } from "../types/graphNode.js";
7
7
  import { IfElse } from "../types/ifElse.js";
8
8
  import { ImportNameType, ImportNodeStatement, ImportStatement } from "../types/importStatement.js";
9
9
  import { MatchBlock } from "../types/matchBlock.js";
@@ -95,7 +95,6 @@ export declare class AgencyGenerator {
95
95
  protected processImportNameType(node: ImportNameType): string;
96
96
  protected processImportNodeStatement(node: ImportNodeStatement): string;
97
97
  private sortAndRenderImports;
98
- protected visibilityToString(vis: Visibility): string;
99
98
  protected processGraphNode(node: GraphNodeDefinition): string;
100
99
  protected processClassDefinition(node: ClassDefinition): string;
101
100
  protected processNewExpression(node: NewExpression): string;
@@ -326,13 +326,14 @@ export class AgencyGenerator {
326
326
  const varName = node.typeHint
327
327
  ? `${node.variableName}${chainStr}: ${variableTypeToString(node.typeHint, this.typeAliases)}${bangSuffix}`
328
328
  : `${node.variableName}${chainStr}`;
329
+ const exportPrefix = node.exported ? "export " : "";
329
330
  const staticPrefix = node.static ? "static " : "";
330
331
  const declPrefix = node.declKind ? `${node.declKind} ` : "";
331
332
  let valueCode = node.value.type === "binOpExpression"
332
333
  ? this.processBinOpExpression(node.value, true).trim()
333
334
  : this.processNode(node.value).trim();
334
335
  return (tags +
335
- this.indentStr(`${staticPrefix}${declPrefix}${varName} = ${valueCode}`));
336
+ this.indentStr(`${exportPrefix}${staticPrefix}${declPrefix}${varName} = ${valueCode}`));
336
337
  }
337
338
  generateLiteral(literal) {
338
339
  switch (literal.type) {
@@ -690,16 +691,6 @@ export class AgencyGenerator {
690
691
  .map((g) => g.map((e) => e.render()).join("\n"));
691
692
  return groups.join("\n\n");
692
693
  }
693
- visibilityToString(vis) {
694
- switch (vis) {
695
- case "public":
696
- return "public ";
697
- case "private":
698
- return "private ";
699
- case undefined:
700
- return "";
701
- }
702
- }
703
694
  processGraphNode(node) {
704
695
  const tags = this.formatAttachedTags(node);
705
696
  const { nodeName, body, parameters } = node;
@@ -707,8 +698,8 @@ export class AgencyGenerator {
707
698
  const returnTypeStr = node.returnType
708
699
  ? ": " + variableTypeToString(node.returnType, this.typeAliases) + returnTypeBang
709
700
  : "";
710
- const visibilityStr = this.visibilityToString(node.visibility);
711
- const prefix = `${visibilityStr}node ${nodeName}`;
701
+ const exportPrefix = node.exported ? "export " : "";
702
+ const prefix = `${exportPrefix}node ${nodeName}`;
712
703
  const renderedParams = this.renderParams(parameters);
713
704
  const signature = this.wrapList(renderedParams, prefix, "(", ")", `${returnTypeStr} {`);
714
705
  let result = this.indentStr(`${signature}\n`);
@@ -351,10 +351,13 @@ export class TypeScriptBuilder {
351
351
  // a separate `__initializeStatic(__ctx)` function (called once from __initializeGlobals).
352
352
  // This gives them access to __ctx for handlers and function dispatch.
353
353
  const staticVarNames = new Set();
354
+ const exportedStaticVarNames = new Set();
354
355
  const staticInitStatements = [];
355
356
  for (const node of program.nodes) {
356
357
  if (node.type === "assignment" && node.scope === "static") {
357
358
  staticVarNames.add(node.variableName);
359
+ if (node.exported)
360
+ exportedStaticVarNames.add(node.variableName);
358
361
  const valueNode = this.processNodeInGlobalInit(node.value);
359
362
  staticInitStatements.push(ts.assign(ts.id(node.variableName), ts.call(ts.id("__deepFreeze"), [valueNode])));
360
363
  }
@@ -363,6 +366,8 @@ export class TypeScriptBuilder {
363
366
  node.statement.scope === "static") {
364
367
  const stmt = node.statement;
365
368
  staticVarNames.add(stmt.variableName);
369
+ if (stmt.exported)
370
+ exportedStaticVarNames.add(stmt.variableName);
366
371
  const valueNode = this.processNodeInGlobalInit(stmt.value);
367
372
  const handler = this.buildHandlerArrow(node.handlerName);
368
373
  staticInitStatements.push(ts.withHandler(handler, ts.assign(ts.id(stmt.variableName), ts.call(ts.id("__deepFreeze"), [valueNode]))));
@@ -427,7 +432,7 @@ export class TypeScriptBuilder {
427
432
  }
428
433
  // Emit static variable `let` declarations at module level + __initializeStatic function
429
434
  if (staticVarNames.size > 0) {
430
- const staticLetDecls = [...staticVarNames].map(name => ts.letDecl(name));
435
+ const staticLetDecls = [...staticVarNames].map(name => exportedStaticVarNames.has(name) ? ts.export(ts.letDecl(name)) : ts.letDecl(name));
431
436
  sections.push(ts.statements([
432
437
  ts.raw("let __staticInitPromise = null"),
433
438
  ...staticLetDecls,
@@ -1453,6 +1458,8 @@ export class TypeScriptBuilder {
1453
1458
  fn: ts.id(implName),
1454
1459
  params: ts.arr(paramNodes),
1455
1460
  toolDefinition: toolDef,
1461
+ safe: ts.bool(!!node.safe),
1462
+ exported: ts.bool(!!node.exported),
1456
1463
  }),
1457
1464
  ts.id("__toolRegistry"),
1458
1465
  ])
@@ -49,7 +49,7 @@ export function parse(contents, config, applyTemplate = true) {
49
49
  const parseResult = parseAgency(contents, config, applyTemplate);
50
50
  // Check if parsing was successful
51
51
  if (!parseResult.success) {
52
- console.error("Failed to parse Agency program.");
52
+ console.error("Failed to parse Agency program.", contents.slice(0, 400));
53
53
  process.exit(1);
54
54
  }
55
55
  return parseResult.result;
@@ -5,7 +5,7 @@ import { parseAgency } from "../parser.js";
5
5
  import { getNodesOfType } from "../utils/node.js";
6
6
  import { DebuggerDriver } from "../debugger/driver.js";
7
7
  import { DebuggerUI } from "../debugger/ui.js";
8
- import { Screen, TerminalInput, TerminalOutput } from "@agency-lang/tui";
8
+ import { Screen, TerminalInput, TerminalOutput } from "../tui/index.js";
9
9
  import { TraceReader } from "../runtime/trace/traceReader.js";
10
10
  import { Checkpoint } from "../runtime/state/checkpointStore.js";
11
11
  import { createDebugInterrupt } from "../runtime/interrupts.js";
@@ -61,6 +61,8 @@ export class LaunchdBackend {
61
61
  name: entry.name,
62
62
  runScriptPath,
63
63
  agentDir: path.dirname(entry.agentFile),
64
+ path: process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin",
65
+ home: os.homedir(),
64
66
  intervals: buildIntervals(entry.cron),
65
67
  logDir: entry.logDir,
66
68
  });
@@ -0,0 +1,14 @@
1
+ export type TestOptions = {
2
+ baseDir?: string;
3
+ cwd?: string;
4
+ };
5
+ export type TestResult = {
6
+ name: string;
7
+ agentFile: string;
8
+ outputFile: string;
9
+ logDir: string;
10
+ };
11
+ export declare const TEST_SCHEDULE_NAME = "agency-cron-test";
12
+ export declare const TEST_OUTPUT_FILE = "agency-cron-test.txt";
13
+ export declare const TEST_AGENT_FILE = "agency-cron-test.agency";
14
+ export declare function scheduleTest(opts?: TestOptions): TestResult;
@@ -0,0 +1,29 @@
1
+ import * as path from "path";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import { scheduleAdd } from "./index.js";
5
+ export const TEST_SCHEDULE_NAME = "agency-cron-test";
6
+ export const TEST_OUTPUT_FILE = "agency-cron-test.txt";
7
+ export const TEST_AGENT_FILE = "agency-cron-test.agency";
8
+ const TEST_AGENT_CONTENT = `import { now } from "std::date"
9
+
10
+ node main() {
11
+ write("${TEST_OUTPUT_FILE}", now()) with approve
12
+ }
13
+ `;
14
+ export function scheduleTest(opts = {}) {
15
+ const cwd = opts.cwd ?? process.cwd();
16
+ const agentFile = path.join(cwd, TEST_AGENT_FILE);
17
+ const outputFile = path.join(cwd, TEST_OUTPUT_FILE);
18
+ fs.writeFileSync(agentFile, TEST_AGENT_CONTENT);
19
+ scheduleAdd({
20
+ file: agentFile,
21
+ every: "minute",
22
+ name: TEST_SCHEDULE_NAME,
23
+ baseDir: opts.baseDir,
24
+ force: true,
25
+ });
26
+ const baseDir = opts.baseDir ?? path.join(os.homedir(), ".agency", "schedules");
27
+ const logDir = path.join(baseDir, TEST_SCHEDULE_NAME, "logs");
28
+ return { name: TEST_SCHEDULE_NAME, agentFile, outputFile, logDir };
29
+ }
@@ -0,0 +1,8 @@
1
+ export declare function serveMcp(file: string, options: {
2
+ name?: string;
3
+ }): Promise<void>;
4
+ export declare function serveHttp(file: string, options: {
5
+ port?: string;
6
+ apiKey?: string;
7
+ standalone?: boolean;
8
+ }): Promise<void>;
@@ -0,0 +1,85 @@
1
+ import path from "path";
2
+ import process from "process";
3
+ import { pathToFileURL } from "url";
4
+ import { compile, loadConfig } from "./commands.js";
5
+ import { SymbolTable } from "../symbolTable.js";
6
+ import { discoverExports } from "../serve/discovery.js";
7
+ import { createMcpHandler, startStdioServer } from "../serve/mcp/adapter.js";
8
+ import { startHttpServer } from "../serve/http/adapter.js";
9
+ import { createLogger } from "../logger.js";
10
+ import { VERSION } from "../version.js";
11
+ import * as esbuild from "esbuild";
12
+ function compileForServe(file) {
13
+ const config = loadConfig();
14
+ const absoluteFile = path.resolve(file);
15
+ const symbolTable = SymbolTable.build(absoluteFile, config);
16
+ const outputPath = compile(config, file, undefined, { symbolTable });
17
+ if (!outputPath) {
18
+ throw new Error(`Compilation failed for ${file}`);
19
+ }
20
+ const fileSymbols = symbolTable.getFile(absoluteFile);
21
+ const exportedNodeNames = Object.values(fileSymbols ?? {})
22
+ .filter((sym) => sym.kind === "node" && sym.exported)
23
+ .map((sym) => sym.name);
24
+ const moduleId = path.relative(process.cwd(), absoluteFile);
25
+ return { outputPath, moduleId, exportedNodeNames };
26
+ }
27
+ async function loadAndDiscover(compileResult) {
28
+ const moduleUrl = pathToFileURL(path.resolve(compileResult.outputPath)).href;
29
+ const mod = await import(moduleUrl);
30
+ const moduleExports = mod;
31
+ const toolRegistry = moduleExports.__toolRegistry ?? {};
32
+ const exports = discoverExports({
33
+ toolRegistry,
34
+ moduleExports,
35
+ moduleId: compileResult.moduleId,
36
+ exportedNodeNames: compileResult.exportedNodeNames,
37
+ });
38
+ return { exports, moduleExports };
39
+ }
40
+ export async function serveMcp(file, options) {
41
+ const compileResult = compileForServe(file);
42
+ const { exports } = await loadAndDiscover(compileResult);
43
+ const serverName = options.name ?? path.basename(file, ".agency");
44
+ const handler = createMcpHandler({
45
+ serverName,
46
+ serverVersion: VERSION,
47
+ exports,
48
+ });
49
+ startStdioServer(handler);
50
+ }
51
+ export async function serveHttp(file, options) {
52
+ const compileResult = compileForServe(file);
53
+ if (options.standalone) {
54
+ await generateStandalone(compileResult.outputPath, file);
55
+ return;
56
+ }
57
+ const { exports, moduleExports } = await loadAndDiscover(compileResult);
58
+ const port = parseInt(options.port ?? "3545", 10);
59
+ if (isNaN(port) || port < 1 || port > 65535) {
60
+ throw new Error(`Invalid port: ${options.port}`);
61
+ }
62
+ const logger = createLogger("info");
63
+ startHttpServer({
64
+ exports,
65
+ port,
66
+ apiKey: options.apiKey,
67
+ logger,
68
+ hasInterrupts: moduleExports.hasInterrupts,
69
+ respondToInterrupts: moduleExports.respondToInterrupts,
70
+ });
71
+ }
72
+ async function generateStandalone(compiledPath, originalFile) {
73
+ const outfile = path.basename(originalFile, ".agency") + ".server.js";
74
+ await esbuild.build({
75
+ entryPoints: [compiledPath],
76
+ bundle: true,
77
+ platform: "node",
78
+ format: "esm",
79
+ outfile,
80
+ banner: {
81
+ js: "// Generated by Agency — standalone HTTP server\n",
82
+ },
83
+ });
84
+ console.log(`Standalone server written to ${outfile}`);
85
+ }
@@ -1,4 +1,5 @@
1
1
  import { AgencyNode } from "./types.js";
2
+ import type { LogLevel } from "./logger.js";
2
3
  import { z } from "zod";
3
4
  export declare const TYPES_THAT_DONT_TRIGGER_NEW_PART: AgencyNode["type"][];
4
5
  /**
@@ -13,6 +14,7 @@ export declare const BUILTIN_VARIABLES: string[];
13
14
  */
14
15
  export interface AgencyConfig {
15
16
  verbose?: boolean;
17
+ logLevel?: LogLevel;
16
18
  outDir?: string;
17
19
  /**
18
20
  * Array of AST node types to exclude from code generation
@@ -121,6 +123,12 @@ export interface AgencyConfig {
121
123
  }
122
124
  export declare const AgencyConfigSchema: z.ZodObject<{
123
125
  verbose: z.ZodOptional<z.ZodBoolean>;
126
+ logLevel: z.ZodOptional<z.ZodEnum<{
127
+ debug: "debug";
128
+ info: "info";
129
+ warn: "warn";
130
+ error: "error";
131
+ }>>;
124
132
  outDir: z.ZodOptional<z.ZodString>;
125
133
  excludeNodeTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
126
134
  excludeBuiltinFunctions: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -136,10 +144,10 @@ export declare const AgencyConfigSchema: z.ZodObject<{
136
144
  }, z.core.$strip>>;
137
145
  client: z.ZodOptional<z.ZodObject<{
138
146
  logLevel: z.ZodOptional<z.ZodEnum<{
139
- error: "error";
140
- warn: "warn";
141
- info: "info";
142
147
  debug: "debug";
148
+ info: "info";
149
+ warn: "warn";
150
+ error: "error";
143
151
  }>>;
144
152
  defaultModel: z.ZodOptional<z.ZodString>;
145
153
  openAiApiKey: z.ZodOptional<z.ZodString>;
@@ -19,6 +19,7 @@ export const BUILTIN_VARIABLES = ["color"];
19
19
  export const AgencyConfigSchema = z
20
20
  .object({
21
21
  verbose: z.boolean(),
22
+ logLevel: z.enum(["debug", "info", "warn", "error"]),
22
23
  outDir: z.string(),
23
24
  excludeNodeTypes: z.array(z.string()),
24
25
  excludeBuiltinFunctions: z.array(z.string()),
@@ -1,4 +1,4 @@
1
- import { type Screen, type Element } from "@agency-lang/tui";
1
+ import { type Screen, type Element } from "../tui/index.js";
2
2
  import type { Checkpoint } from "../runtime/state/checkpointStore.js";
3
3
  import type { UIState } from "./uiState.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { box, row, column, text, escapeStyleTags, } from "@agency-lang/tui";
1
+ import { box, row, column, text, escapeStyleTags, } from "../tui/index.js";
2
2
  import { formatValue } from "./util.js";
3
3
  // ---------------------------------------------------------------------------
4
4
  // Rewind selector
@@ -1,4 +1,4 @@
1
- import { FrameRecorder, type Frame } from "@agency-lang/tui";
1
+ import { FrameRecorder, type Frame } from "../tui/index.js";
2
2
  import { DebuggerDriver } from "./driver.js";
3
3
  import { DebuggerUI } from "./ui.js";
4
4
  import type { Checkpoint } from "../runtime/state/checkpointStore.js";
@@ -1,4 +1,4 @@
1
- import { Screen, FrameRecorder, } from "@agency-lang/tui";
1
+ import { Screen, FrameRecorder, } from "../tui/index.js";
2
2
  import { DebuggerDriver } from "./driver.js";
3
3
  import { DebuggerUI } from "./ui.js";
4
4
  import { hasInterrupts, createDebugInterrupt } from "../runtime/interrupts.js";
@@ -1,4 +1,4 @@
1
- import { Screen, type Element, type Frame } from "@agency-lang/tui";
1
+ import { Screen, type Element, type Frame } from "../tui/index.js";
2
2
  import type { Checkpoint } from "../runtime/state/checkpointStore.js";
3
3
  import type { FunctionParameter } from "../types.js";
4
4
  import type { DebuggerCommand, DebuggerIO } from "./types.js";
@@ -1,4 +1,4 @@
1
- import { box, row, column, text, escapeStyleTags, } from "@agency-lang/tui";
1
+ import { box, row, column, text, escapeStyleTags, } from "../tui/index.js";
2
2
  import { readFileSync } from "fs";
3
3
  import { formatTypeHint } from "../cli/util.js";
4
4
  import { UIState } from "./uiState.js";
@@ -0,0 +1,8 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ export type Logger = {
3
+ debug: (message: string) => void;
4
+ info: (message: string) => void;
5
+ warn: (message: string) => void;
6
+ error: (message: string) => void;
7
+ };
8
+ export declare function createLogger(level?: LogLevel): Logger;
@@ -0,0 +1,21 @@
1
+ const LEVEL_ORDER = {
2
+ debug: 0,
3
+ info: 1,
4
+ warn: 2,
5
+ error: 3,
6
+ };
7
+ export function createLogger(level = "info") {
8
+ const threshold = LEVEL_ORDER[level];
9
+ function log(msgLevel, message) {
10
+ if (LEVEL_ORDER[msgLevel] < threshold)
11
+ return;
12
+ const timestamp = new Date().toISOString().replace("T", " ").replace("Z", "");
13
+ process.stderr.write(`[${timestamp}] ${msgLevel.toUpperCase()} ${message}\n`);
14
+ }
15
+ return {
16
+ debug: (msg) => log("debug", msg),
17
+ info: (msg) => log("info", msg),
18
+ warn: (msg) => log("warn", msg),
19
+ error: (msg) => log("error", msg),
20
+ };
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { createLogger } from "./logger.js";
3
+ describe("createLogger", () => {
4
+ let spy;
5
+ beforeEach(() => {
6
+ spy = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
7
+ });
8
+ afterEach(() => spy.mockRestore());
9
+ it("logs at info level by default", () => {
10
+ const log = createLogger("info");
11
+ log.info("hello");
12
+ expect(spy).toHaveBeenCalledTimes(1);
13
+ expect(spy.mock.calls[0][0]).toContain("hello");
14
+ });
15
+ it("suppresses debug when level is info", () => {
16
+ const log = createLogger("info");
17
+ log.debug("hidden");
18
+ expect(spy).not.toHaveBeenCalled();
19
+ });
20
+ it("shows debug when level is debug", () => {
21
+ const log = createLogger("debug");
22
+ log.debug("visible");
23
+ expect(spy).toHaveBeenCalledTimes(1);
24
+ });
25
+ it("suppresses info when level is warn", () => {
26
+ const log = createLogger("warn");
27
+ log.warn("caution");
28
+ expect(spy).toHaveBeenCalledTimes(1);
29
+ log.info("suppressed");
30
+ expect(spy).toHaveBeenCalledTimes(1);
31
+ });
32
+ it("suppresses warn when level is error", () => {
33
+ const log = createLogger("error");
34
+ log.error("bad");
35
+ expect(spy).toHaveBeenCalledTimes(1);
36
+ log.warn("suppressed");
37
+ expect(spy).toHaveBeenCalledTimes(1);
38
+ });
39
+ it("includes level label in output", () => {
40
+ const log = createLogger("debug");
41
+ log.warn("test");
42
+ expect(spy.mock.calls[0][0]).toContain("WARN");
43
+ });
44
+ });
@@ -165,6 +165,8 @@ function formatSignature(symbol) {
165
165
  : `type ${symbol.name}`;
166
166
  case "class":
167
167
  return `class ${symbol.name}`;
168
+ case "constant":
169
+ return `static const ${symbol.name}${symbol.returnType ? `: ${formatTypeHint(symbol.returnType)}` : ""}`;
168
170
  }
169
171
  }
170
172
  export function formatSemanticHover(symbol) {
@@ -1,8 +1,8 @@
1
1
  import { capture, eof, failure, getErrorMessage, many, map, or, seqC, set, setInputStr, setTraceHost, setTraceId, success, TarsecError, trace, } from "tarsec";
2
2
  import { nanoid } from "nanoid";
3
3
  import render from "./templates/backends/agency/template.js";
4
- import { assignmentParser, binOpParser, booleanParser, commentParser, debuggerParser, forLoopParser, functionParser, gotoStatementParser, graphNodeParser, handleBlockParser, ifParser, importNodeStatmentParser, importStatmentParser, interruptStatementParser, keywordParser, matchBlockParser, messageThreadParser, multiLineCommentParser, newLineParser, blankLineParser, BLANK_LINE_SENTINEL, optionalSpacesOrNewline, returnStatementParser, staticAssignmentParser, skillParser, tagParser, typeAliasParser, valueAccessParser, whileLoopParser, withModifierParser, classParser, AGENCY_TEMPLATE_OFFSET, setTemplateOffset, } from "./parsers/parsers.js";
5
- const nodeParser = or(keywordParser, importNodeStatmentParser, importStatmentParser, graphNodeParser, classParser, typeAliasParser, ifParser, forLoopParser, whileLoopParser, matchBlockParser, messageThreadParser, handleBlockParser, debuggerParser, skillParser, functionParser, returnStatementParser, gotoStatementParser, interruptStatementParser, tagParser, withModifierParser, staticAssignmentParser, assignmentParser, binOpParser, booleanParser, valueAccessParser, multiLineCommentParser, commentParser, blankLineParser, newLineParser);
4
+ import { assignmentParser, binOpParser, booleanParser, commentParser, debuggerParser, forLoopParser, functionParser, gotoStatementParser, graphNodeParser, handleBlockParser, ifParser, importNodeStatmentParser, importStatmentParser, interruptStatementParser, keywordParser, matchBlockParser, messageThreadParser, multiLineCommentParser, newLineParser, blankLineParser, BLANK_LINE_SENTINEL, optionalSpacesOrNewline, returnStatementParser, modifiedAssignmentParser, skillParser, tagParser, typeAliasParser, valueAccessParser, whileLoopParser, withModifierParser, classParser, AGENCY_TEMPLATE_OFFSET, setTemplateOffset, } from "./parsers/parsers.js";
5
+ const nodeParser = or(keywordParser, importNodeStatmentParser, importStatmentParser, graphNodeParser, classParser, typeAliasParser, ifParser, forLoopParser, whileLoopParser, matchBlockParser, messageThreadParser, handleBlockParser, debuggerParser, skillParser, functionParser, returnStatementParser, gotoStatementParser, interruptStatementParser, tagParser, withModifierParser, modifiedAssignmentParser, assignmentParser, binOpParser, booleanParser, valueAccessParser, multiLineCommentParser, commentParser, blankLineParser, newLineParser);
6
6
  export const agencyNode = (input) => {
7
7
  const parser = many(trace("agencyParser", map(seqC(capture(nodeParser, "node"), optionalSpacesOrNewline), (result) => result.node)));
8
8
  return parser(input);
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { assignmentParser, staticAssignmentParser } from "./parsers.js";
2
+ import { assignmentParser, modifiedAssignmentParser } from "./parsers.js";
3
3
  describe("assignmentParser", () => {
4
4
  const testCases = [
5
5
  // Happy path - simple literal assignments
@@ -564,9 +564,9 @@ describe("assignmentParser", () => {
564
564
  }
565
565
  });
566
566
  });
567
- describe("staticAssignmentParser", () => {
567
+ describe("modifiedAssignmentParser", () => {
568
568
  it("should parse static const with a number", () => {
569
- const result = staticAssignmentParser("static const x = 42");
569
+ const result = modifiedAssignmentParser("static const x = 42");
570
570
  expect(result.success).toBe(true);
571
571
  if (result.success) {
572
572
  expect(result.result.type).toBe("assignment");
@@ -577,7 +577,7 @@ describe("staticAssignmentParser", () => {
577
577
  }
578
578
  });
579
579
  it("should parse static const with a string", () => {
580
- const result = staticAssignmentParser('static const name = "Alice"');
580
+ const result = modifiedAssignmentParser('static const name = "Alice"');
581
581
  expect(result.success).toBe(true);
582
582
  if (result.success) {
583
583
  expect(result.result.static).toBe(true);
@@ -586,7 +586,7 @@ describe("staticAssignmentParser", () => {
586
586
  }
587
587
  });
588
588
  it("should parse static const with a function call", () => {
589
- const result = staticAssignmentParser('static const myPrompt = read("prompt.md")');
589
+ const result = modifiedAssignmentParser('static const myPrompt = read("prompt.md")');
590
590
  expect(result.success).toBe(true);
591
591
  if (result.success) {
592
592
  expect(result.result.static).toBe(true);
@@ -596,19 +596,19 @@ describe("staticAssignmentParser", () => {
596
596
  }
597
597
  });
598
598
  it("should reject static let", () => {
599
- const result = staticAssignmentParser("static let x = 42");
599
+ const result = modifiedAssignmentParser("static let x = 42");
600
600
  expect(result.success).toBe(false);
601
601
  });
602
602
  it("should reject static without const", () => {
603
- const result = staticAssignmentParser("static x = 42");
603
+ const result = modifiedAssignmentParser("static x = 42");
604
604
  expect(result.success).toBe(false);
605
605
  });
606
606
  it("should not parse a regular assignment", () => {
607
- const result = staticAssignmentParser("x = 42");
607
+ const result = modifiedAssignmentParser("x = 42");
608
608
  expect(result.success).toBe(false);
609
609
  });
610
610
  it("should not parse const without static", () => {
611
- const result = staticAssignmentParser("const x = 42");
611
+ const result = modifiedAssignmentParser("const x = 42");
612
612
  expect(result.success).toBe(false);
613
613
  });
614
614
  it("regular assignmentParser should not set static", () => {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { modifiedAssignmentParser } from "./parsers.js";
3
+ describe("export const", () => {
4
+ it("parses export const", () => {
5
+ const result = modifiedAssignmentParser(`export const x = 5\n`);
6
+ expect(result.success).toBe(true);
7
+ if (result.success) {
8
+ expect(result.result.exported).toBe(true);
9
+ expect(result.result.declKind).toBe("const");
10
+ expect(result.result.variableName).toBe("x");
11
+ }
12
+ });
13
+ it("parses export static const", () => {
14
+ const result = modifiedAssignmentParser(`export static const x = 5\n`);
15
+ expect(result.success).toBe(true);
16
+ if (result.success) {
17
+ expect(result.result.exported).toBe(true);
18
+ expect(result.result.static).toBe(true);
19
+ expect(result.result.declKind).toBe("const");
20
+ }
21
+ });
22
+ it("parses static export const (any order)", () => {
23
+ const result = modifiedAssignmentParser(`static export const x = 5\n`);
24
+ expect(result.success).toBe(true);
25
+ if (result.success) {
26
+ expect(result.result.exported).toBe(true);
27
+ expect(result.result.static).toBe(true);
28
+ expect(result.result.declKind).toBe("const");
29
+ }
30
+ });
31
+ // The parser accepts export let syntactically; the typechecker is responsible
32
+ // for rejecting it (export only makes sense for const declarations).
33
+ it("parses export let (typechecker rejects this, not parser)", () => {
34
+ const result = modifiedAssignmentParser(`export let x = 5\n`);
35
+ expect(result.success).toBe(true);
36
+ if (result.success) {
37
+ expect(result.result.exported).toBe(true);
38
+ expect(result.result.declKind).toBe("let");
39
+ }
40
+ });
41
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { graphNodeParser, functionParser } from "./parsers.js";
3
+ describe("export node", () => {
4
+ it("parses export node", () => {
5
+ const result = graphNodeParser(`export node main() {\n print("hello")\n}`);
6
+ expect(result.success).toBe(true);
7
+ if (result.success) {
8
+ expect(result.result.exported).toBe(true);
9
+ expect(result.result.nodeName).toBe("main");
10
+ }
11
+ });
12
+ it("parses node without export", () => {
13
+ const result = graphNodeParser(`node main() {\n print("hello")\n}`);
14
+ expect(result.success).toBe(true);
15
+ if (result.success) {
16
+ expect(result.result.exported).toBeUndefined();
17
+ }
18
+ });
19
+ });
20
+ describe("function modifier order", () => {
21
+ it("parses export safe def", () => {
22
+ const result = functionParser(`export safe def foo() {\n return 1\n}`);
23
+ expect(result.success).toBe(true);
24
+ if (result.success) {
25
+ expect(result.result.exported).toBe(true);
26
+ expect(result.result.safe).toBe(true);
27
+ }
28
+ });
29
+ it("parses safe export def (any order)", () => {
30
+ const result = functionParser(`safe export def foo() {\n return 1\n}`);
31
+ expect(result.success).toBe(true);
32
+ if (result.success) {
33
+ expect(result.result.exported).toBe(true);
34
+ expect(result.result.safe).toBe(true);
35
+ }
36
+ });
37
+ });
@@ -129,7 +129,7 @@ export declare const matchBlockParser: Parser<{
129
129
  export declare const importNodeStatmentParser: Parser<ImportNodeStatement>;
130
130
  export declare const importStatmentParser: Parser<ImportStatement>;
131
131
  export declare const assignmentParser: Parser<Assignment>;
132
- export declare const staticAssignmentParser: Parser<Assignment>;
132
+ export declare const modifiedAssignmentParser: Parser<Assignment>;
133
133
  export declare const docStringParser: Parser<DocString>;
134
134
  export declare const bodyParser: (input: string) => ParserResult<AgencyNode[]>;
135
135
  export declare const _messageThreadParser: Parser<MessageThread>;