@harperfast/agent 0.16.14 → 0.16.16

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.
@@ -712,7 +712,6 @@ function getEnv(newKey, oldKey) {
712
712
  // tools/harper/getHarperSkillTool.ts
713
713
  import { ruleNames, rules, skillSummary } from "@harperfast/skills";
714
714
  import { tool as tool10 } from "@openai/agents";
715
- import "fs";
716
715
  import { z as z10 } from "zod";
717
716
  var skillLinkRegex = /\[[^\]]+]\((?:rules|skills)\/([^)]+)\.md\)/g;
718
717
  var skills = ruleNames;
@@ -749,7 +748,7 @@ async function execute10({ skill }) {
749
748
 
750
749
  // tools/files/workspaceEditor.ts
751
750
  import { applyDiff } from "@openai/agents";
752
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
751
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
753
752
  import { mkdir, rm, writeFile } from "fs/promises";
754
753
  import path5 from "path";
755
754
 
@@ -771,14 +770,14 @@ function normalizeDiff(diff) {
771
770
  import path3 from "path";
772
771
 
773
772
  // utils/files/aiignore.ts
774
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
773
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
775
774
  import path2 from "path";
776
775
  var ignorePatterns = [];
777
776
  function loadAiIgnore() {
778
777
  const ignorePath = path2.join(trackedState.cwd, ".aiignore");
779
778
  if (existsSync5(ignorePath)) {
780
779
  try {
781
- const content = readFileSync3(ignorePath, "utf8");
780
+ const content = readFileSync2(ignorePath, "utf8");
782
781
  ignorePatterns = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((pattern) => pattern.endsWith("/") || pattern.endsWith("\\") ? pattern.slice(0, -1) : pattern);
783
782
  } catch (error) {
784
783
  logError(error);
@@ -832,18 +831,22 @@ function resolvePath(root, relativePath) {
832
831
  }
833
832
 
834
833
  // utils/files/validateGraphQL.ts
835
- import { buildSchema, extendSchema, parse, validateSchema } from "graphql";
836
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
834
+ import { extendSchema, parse, validateSchema } from "graphql";
835
+
836
+ // utils/files/getHarperSchema.ts
837
+ import { buildSchema } from "graphql";
838
+ import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
837
839
  import path4 from "path";
838
840
  import { fileURLToPath } from "url";
839
841
  var __dirname = path4.dirname(fileURLToPath(import.meta.url));
840
842
  var cachedSchema = null;
841
- function getHarperSchema(root) {
843
+ function getHarperSchemaContent(root) {
842
844
  if (cachedSchema) {
843
845
  return cachedSchema;
844
846
  }
845
847
  const paths = [
846
848
  path4.join(root, "node_modules", "harperdb", "schema.graphql"),
849
+ path4.join(root, "node_modules", "harper", "schema.graphql"),
847
850
  path4.join(__dirname, "schema.graphql"),
848
851
  path4.join(__dirname, "..", "schema.graphql"),
849
852
  path4.join(__dirname, "..", "..", "schema.graphql")
@@ -851,9 +854,7 @@ function getHarperSchema(root) {
851
854
  for (const schemaPath of paths) {
852
855
  if (existsSync6(schemaPath)) {
853
856
  try {
854
- const schemaSource = readFileSync4(schemaPath, "utf8");
855
- cachedSchema = buildSchema(schemaSource, { assumeValidSDL: true });
856
- return cachedSchema;
857
+ return readFileSync3(schemaPath, "utf8");
857
858
  } catch (e) {
858
859
  console.error(`Error parsing HarperDB schema at ${schemaPath}:`, e);
859
860
  }
@@ -861,13 +862,26 @@ function getHarperSchema(root) {
861
862
  }
862
863
  return null;
863
864
  }
865
+ function getHarperSchemaBuilt(root) {
866
+ if (cachedSchema) {
867
+ return cachedSchema;
868
+ }
869
+ const schemaSource = getHarperSchemaContent(root);
870
+ if (schemaSource) {
871
+ cachedSchema = buildSchema(schemaSource, { assumeValidSDL: true });
872
+ return cachedSchema;
873
+ }
874
+ return null;
875
+ }
876
+
877
+ // utils/files/validateGraphQL.ts
864
878
  function validateGraphQL(content, filePath, root) {
865
879
  if (!filePath.endsWith(".graphql")) {
866
880
  return null;
867
881
  }
868
882
  try {
869
883
  const document2 = parse(content);
870
- const schema = getHarperSchema(root);
884
+ const schema = getHarperSchemaBuilt(root);
871
885
  if (schema) {
872
886
  const extendedSchema = extendSchema(schema, document2, { assumeValidSDL: false });
873
887
  const errors = validateSchema(extendedSchema).filter(
@@ -917,7 +931,7 @@ ${validationError}`;
917
931
  if (!existsSync7(targetPath)) {
918
932
  return { status: "failed", output: "Error: file not found at path " + targetPath };
919
933
  }
920
- const original = readFileSync5(targetPath, "utf8");
934
+ const original = readFileSync4(targetPath, "utf8");
921
935
  const normalizedDiff = normalizeDiff(operation.diff);
922
936
  const patched = applyDiff(original, normalizedDiff);
923
937
  await writeFile(targetPath, patched, "utf8");
@@ -1387,7 +1401,7 @@ import { tool as tool19 } from "@openai/agents";
1387
1401
  import { z as z19 } from "zod";
1388
1402
 
1389
1403
  // utils/files/updateEnv.ts
1390
- import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync } from "fs";
1404
+ import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync } from "fs";
1391
1405
  import { homedir as homedir3 } from "os";
1392
1406
  import { dirname as dirname3, join as join6 } from "path";
1393
1407
  function updateEnv(key, value) {
@@ -1402,7 +1416,7 @@ function updateEnv(key, value) {
1402
1416
  }
1403
1417
  let envContent = "";
1404
1418
  if (existsSync8(envPath)) {
1405
- envContent = readFileSync6(envPath, "utf8");
1419
+ envContent = readFileSync5(envPath, "utf8");
1406
1420
  }
1407
1421
  const regex = new RegExp(`^${key}=.*`, "m");
1408
1422
  if (regex.test(envContent)) {
@@ -2066,9 +2080,6 @@ var getHarperResourceInterfaceTool = tool33({
2066
2080
 
2067
2081
  // tools/harper/getHarperSchemaGraphQLTool.ts
2068
2082
  import { tool as tool34 } from "@openai/agents";
2069
- import { readFile as readFile4 } from "fs/promises";
2070
- import { createRequire as createRequire3 } from "module";
2071
- import { dirname as dirname6, join as join9 } from "path";
2072
2083
  import { z as z34 } from "zod";
2073
2084
  var ToolParameters21 = z34.object({});
2074
2085
  var getHarperSchemaGraphQLTool = tool34({
@@ -2077,13 +2088,7 @@ var getHarperSchemaGraphQLTool = tool34({
2077
2088
  parameters: ToolParameters21,
2078
2089
  async execute() {
2079
2090
  try {
2080
- return await readFile4(
2081
- join9(
2082
- dirname6(createRequire3(import.meta.url).resolve("harperdb")),
2083
- `schema.graphql`
2084
- ),
2085
- "utf8"
2086
- );
2091
+ return getHarperSchemaContent(trackedState.cwd);
2087
2092
  } catch (error) {
2088
2093
  return `Error reading HarperDB GraphQL schema: ${error}`;
2089
2094
  }
@@ -2548,8 +2553,8 @@ Stack: ${String(err.stack).split("\n").slice(0, 8).join("\n")}` : "";
2548
2553
  // utils/sessions/DiskSession.ts
2549
2554
  import { MemorySession } from "@openai/agents";
2550
2555
  import { existsSync as existsSync10 } from "fs";
2551
- import { mkdir as mkdir2, readFile as readFile5, rename, writeFile as writeFile3 } from "fs/promises";
2552
- import { dirname as dirname7 } from "path";
2556
+ import { mkdir as mkdir2, readFile as readFile4, rename, writeFile as writeFile3 } from "fs/promises";
2557
+ import { dirname as dirname6 } from "path";
2553
2558
  var DiskSession = class extends MemorySession {
2554
2559
  filePath;
2555
2560
  ready;
@@ -2600,7 +2605,7 @@ var DiskSession = class extends MemorySession {
2600
2605
  async loadStorage() {
2601
2606
  if (existsSync10(this.filePath)) {
2602
2607
  try {
2603
- const data = await readFile5(this.filePath, "utf-8");
2608
+ const data = await readFile4(this.filePath, "utf-8");
2604
2609
  const parsed = JSON.parse(data);
2605
2610
  parsed.sessions = parsed.sessions || {};
2606
2611
  parsed.skillsRead = parsed.skillsRead || {};
@@ -2615,7 +2620,7 @@ var DiskSession = class extends MemorySession {
2615
2620
  async updateStorage(update) {
2616
2621
  const storage = await this.loadStorage();
2617
2622
  update(storage);
2618
- const dir = dirname7(this.filePath);
2623
+ const dir = dirname6(this.filePath);
2619
2624
  if (!existsSync10(dir)) {
2620
2625
  await mkdir2(dir, { recursive: true });
2621
2626
  }
@@ -4051,6 +4056,7 @@ export {
4051
4056
  defaultOllamaModel,
4052
4057
  defaultOllamaCompactionModel,
4053
4058
  isOpenAIModel,
4059
+ getProvider,
4054
4060
  handleExit,
4055
4061
  setupGlobalErrorHandlers,
4056
4062
  updateEnv,
package/dist/cli.js CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  emitToListeners,
16
16
  excludeFalsy,
17
17
  fetchOllamaModels,
18
+ getProvider,
18
19
  handleExit,
19
20
  isOpenAIModel,
20
21
  isTrue,
@@ -26,7 +27,7 @@ import {
26
27
  updateEnv,
27
28
  useActions,
28
29
  useListener
29
- } from "./chunk-SEYUVI2L.js";
30
+ } from "./chunk-HQGGUF5D.js";
30
31
 
31
32
  // lifecycle/patchFetch.ts
32
33
  var originalFetch = globalThis.fetch;
@@ -85,6 +86,249 @@ import chalk5 from "chalk";
85
86
  import { render, useApp } from "ink";
86
87
  import "react";
87
88
 
89
+ // utils/models/deprecations.ts
90
+ import chalk from "chalk";
91
+ var DEPRECATION_RULES = [
92
+ // Redirect any gpt-4o variants (including dated and -mini) to gpt-5-nano
93
+ {
94
+ match: (name) => name.toLowerCase().startsWith("gpt-4o"),
95
+ replacement: "gpt-5-nano",
96
+ reason: "OpenAI gpt-4o family is deprecated in this agent"
97
+ }
98
+ ];
99
+ function getDeprecatedReplacement(modelName) {
100
+ if (!modelName) {
101
+ return null;
102
+ }
103
+ for (const rule of DEPRECATION_RULES) {
104
+ if (rule.match(modelName)) {
105
+ return { replacement: rule.replacement, rule };
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+ function warnAndPersistRedirect(original, envKey, replacement, reason) {
111
+ const reasonSuffix = reason ? ` Reason: ${reason}.` : "";
112
+ console.warn(
113
+ chalk.yellow(
114
+ `Warning: model "${original}" is deprecated and will be redirected to "${replacement}". Your environment setting (${envKey}) has been updated.${reasonSuffix}`
115
+ )
116
+ );
117
+ updateEnv(envKey, replacement);
118
+ }
119
+
120
+ // utils/shell/cli.ts
121
+ import chalk2 from "chalk";
122
+
123
+ // utils/package/getOwnPackageJson.ts
124
+ import { readFileSync } from "fs";
125
+ import { join } from "path";
126
+ import { fileURLToPath } from "url";
127
+ var __dirname = fileURLToPath(new URL(".", import.meta.url));
128
+ function getOwnPackageJson() {
129
+ try {
130
+ const packageContents = readFileSync(join(__dirname, "../package.json"), "utf8");
131
+ return JSON.parse(packageContents);
132
+ } catch {
133
+ return { name: "@harperfast/agent", version: "0.0.0" };
134
+ }
135
+ }
136
+
137
+ // utils/shell/cli.ts
138
+ function isHelpRequest(args) {
139
+ const helpVariants = ["--help", "-h", "help"];
140
+ return args.some((arg) => helpVariants.includes(arg.toLowerCase()));
141
+ }
142
+ function isVersionRequest(args) {
143
+ const versionVariants = ["--version", "-v", "version"];
144
+ return args.some((arg) => versionVariants.includes(arg.toLowerCase()));
145
+ }
146
+ function handleHelp() {
147
+ console.log(`
148
+ ${chalk2.bold("harper-agent")} - AI to help you with Harper app creation and modification
149
+
150
+ ${chalk2.bold("USAGE")}
151
+ $ harper-agent [options]
152
+ $ harper-agent [command]
153
+
154
+ ${chalk2.bold("OPTIONS")}
155
+ -h, --help Show help information
156
+ -v, --version Show version information
157
+ -m, --model Specify the model to use (e.g., ${defaultOpenAIModel}, ${defaultAnthropicModel}, ${defaultOllamaModel})
158
+ Can also be set via HARPER_AGENT_MODEL environment variable.
159
+ For Ollama, use the ollama- prefix (e.g., ${defaultOllamaCompactionModel}).
160
+ -c, --compaction-model Specify the compaction model to use (defaults to ${defaultOpenAICompactionModel}).
161
+ Can also be set via HARPER_AGENT_COMPACTION_MODEL environment variable.
162
+ -s, --session Specify a path to a SQLite database file to persist the chat session.
163
+ Can also be set via HARPER_AGENT_SESSION environment variable.
164
+ --max-turns Specify the maximum number of turns for the agent run.
165
+ Can also be set via HARPER_AGENT_MAX_TURNS environment variable.
166
+ --max-cost Specify the maximum cost (in USD) for the agent run.
167
+ If exceeded, the agent will exit with a non-zero code.
168
+ Can also be set via HARPER_AGENT_MAX_COST environment variable.
169
+ --flex-tier Force the use of the flex service tier for lower costs but potentially
170
+ more errors under high system load.
171
+ Can also be set via HARPER_AGENT_FLEX_TIER=true environment variable.
172
+ -p, --prompt Specify a prompt to be executed autonomously until completion.
173
+
174
+ ${chalk2.bold("COMMANDS")}
175
+ --help Show help information
176
+ --version Show version information
177
+
178
+ ${chalk2.bold("EXAMPLES")}
179
+ $ harper-agent --help
180
+ $ harper-agent --version
181
+ $ harper-agent
182
+ `);
183
+ process.exit(0);
184
+ }
185
+ function handleVersion() {
186
+ const pkg = getOwnPackageJson();
187
+ console.log(pkg.version);
188
+ process.exit(0);
189
+ }
190
+
191
+ // lifecycle/parseArgs.ts
192
+ function stripQuotes(str) {
193
+ if (str.startsWith('"') && str.endsWith('"') || str.startsWith("'") && str.endsWith("'")) {
194
+ return str.slice(1, -1);
195
+ }
196
+ return str;
197
+ }
198
+ function parseArgs() {
199
+ const args = process.argv.slice(2);
200
+ if (isHelpRequest(args)) {
201
+ handleHelp();
202
+ }
203
+ if (isVersionRequest(args)) {
204
+ handleVersion();
205
+ }
206
+ for (let i = 0; i < args.length; i++) {
207
+ const arg = args[i];
208
+ const flagPairs = [
209
+ ["model", ["--model", "-m", "model"]],
210
+ ["compactionModel", ["--compaction-model", "-c", "compaction-model"]],
211
+ ["sessionPath", ["--session", "-s", "session"]],
212
+ ["maxTurns", ["--max-turns"]],
213
+ ["maxCost", ["--max-cost"]],
214
+ ["rateLimitThreshold", ["--rate-limit-threshold"]],
215
+ ["prompt", ["--prompt", "-p"]]
216
+ ];
217
+ let handled = false;
218
+ for (const [key, prefixes] of flagPairs) {
219
+ for (const prefix of prefixes) {
220
+ if (arg === prefix) {
221
+ if (args[i + 1]) {
222
+ const val = stripQuotes(args[++i]);
223
+ if (key === "maxTurns" || key === "maxCost" || key === "rateLimitThreshold") {
224
+ trackedState[key] = parseFloat(val);
225
+ } else {
226
+ trackedState[key] = val;
227
+ }
228
+ }
229
+ handled = true;
230
+ break;
231
+ } else if (arg.startsWith(`${prefix}=`)) {
232
+ const val = stripQuotes(arg.slice(prefix.length + 1));
233
+ if (key === "maxTurns" || key === "maxCost" || key === "rateLimitThreshold") {
234
+ trackedState[key] = parseFloat(val);
235
+ } else {
236
+ trackedState[key] = val;
237
+ }
238
+ handled = true;
239
+ break;
240
+ }
241
+ }
242
+ if (handled) {
243
+ break;
244
+ }
245
+ }
246
+ if (handled) {
247
+ continue;
248
+ }
249
+ if (arg === "--flex-tier") {
250
+ trackedState.useFlexTier = true;
251
+ } else if (arg === "--no-monitor-rate-limits") {
252
+ trackedState.monitorRateLimits = false;
253
+ } else if (arg === "--autonomous" || arg === "-a") {
254
+ trackedState.autonomous = true;
255
+ }
256
+ }
257
+ if (!trackedState.model && process.env.HARPER_AGENT_MODEL) {
258
+ trackedState.model = process.env.HARPER_AGENT_MODEL;
259
+ }
260
+ if (!trackedState.compactionModel && process.env.HARPER_AGENT_COMPACTION_MODEL) {
261
+ trackedState.compactionModel = process.env.HARPER_AGENT_COMPACTION_MODEL;
262
+ }
263
+ if (!trackedState.sessionPath && process.env.HARPER_AGENT_SESSION) {
264
+ trackedState.sessionPath = process.env.HARPER_AGENT_SESSION;
265
+ }
266
+ if (process.env.HARPER_AGENT_MAX_TURNS) {
267
+ trackedState.maxTurns = parseFloat(process.env.HARPER_AGENT_MAX_TURNS);
268
+ }
269
+ if (process.env.HARPER_AGENT_MAX_COST) {
270
+ trackedState.maxCost = parseFloat(process.env.HARPER_AGENT_MAX_COST);
271
+ }
272
+ if (process.env.HARPER_AGENT_RATE_LIMIT_THRESHOLD) {
273
+ trackedState.rateLimitThreshold = parseFloat(process.env.HARPER_AGENT_RATE_LIMIT_THRESHOLD);
274
+ }
275
+ if (process.env.HARPER_AGENT_MONITOR_RATE_LIMITS === "false") {
276
+ trackedState.monitorRateLimits = false;
277
+ }
278
+ if (!trackedState.useFlexTier && isTrue(process.env.HARPER_AGENT_FLEX_TIER)) {
279
+ trackedState.useFlexTier = true;
280
+ }
281
+ if (isTrue(process.env.HARPER_AGENT_AUTO_APPROVE_CODE_INTERPRETER)) {
282
+ trackedState.autoApproveCodeInterpreter = true;
283
+ }
284
+ if (isTrue(process.env.HARPER_AGENT_AUTO_APPROVE_PATCHES)) {
285
+ trackedState.autoApprovePatches = true;
286
+ }
287
+ if (isTrue(process.env.HARPER_AGENT_AUTO_APPROVE_SHELL)) {
288
+ trackedState.autoApproveShell = true;
289
+ }
290
+ if (isTrue(process.env.HARPER_AGENT_AUTONOMOUS)) {
291
+ trackedState.autonomous = true;
292
+ }
293
+ if (!trackedState.model || trackedState.model === defaultModelToken) {
294
+ if (process.env.ANTHROPIC_API_KEY) {
295
+ trackedState.model = defaultAnthropicModel;
296
+ } else if (process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
297
+ trackedState.model = defaultGoogleModel;
298
+ } else if (process.env.OLLAMA_BASE_URL) {
299
+ trackedState.model = defaultOllamaModel;
300
+ } else {
301
+ trackedState.model = defaultOpenAIModel;
302
+ }
303
+ }
304
+ if (!trackedState.compactionModel || trackedState.compactionModel === defaultModelToken) {
305
+ const m = trackedState.model;
306
+ if (m.startsWith("claude-")) {
307
+ trackedState.compactionModel = defaultAnthropicCompactionModel;
308
+ } else if (m.startsWith("gemini-")) {
309
+ trackedState.compactionModel = defaultGoogleCompactionModel;
310
+ } else if (m.startsWith("ollama-")) {
311
+ trackedState.compactionModel = defaultOllamaCompactionModel;
312
+ } else {
313
+ trackedState.compactionModel = defaultOpenAICompactionModel;
314
+ }
315
+ }
316
+ if (!isOpenAIModel(trackedState.model)) {
317
+ process.env.OPENAI_AGENTS_DISABLE_TRACING = process.env.OPENAI_AGENTS_DISABLE_TRACING || "1";
318
+ }
319
+ const maybeRedirect = (current, envKey) => {
320
+ const hit = getDeprecatedReplacement(current);
321
+ if (hit) {
322
+ const { replacement, rule } = hit;
323
+ warnAndPersistRedirect(current, envKey, replacement, rule.reason);
324
+ return replacement;
325
+ }
326
+ return current;
327
+ };
328
+ trackedState.model = maybeRedirect(trackedState.model, "HARPER_AGENT_MODEL");
329
+ trackedState.compactionModel = maybeRedirect(trackedState.compactionModel, "HARPER_AGENT_COMPACTION_MODEL");
330
+ }
331
+
88
332
  // ink/components/ChatContent.tsx
89
333
  import { Spinner as Spinner2 } from "@inkjs/ui";
90
334
  import { Box as Box10, Text as Text10, useInput as useInput4 } from "ink";
@@ -1067,7 +1311,7 @@ function SettingsView({ isDense = false }) {
1067
1311
  {
1068
1312
  label: "<edit settings>",
1069
1313
  isAction: true,
1070
- action: bootstrapConfig
1314
+ action: showConfigThenReparse
1071
1315
  }
1072
1316
  ], [autoApproveCodeInterpreter, autoApprovePatches, autoApproveShell, monitorRateLimits]);
1073
1317
  useInput2((_input, key) => {
@@ -1180,7 +1424,7 @@ function SettingsView({ isDense = false }) {
1180
1424
  ] })
1181
1425
  ] }),
1182
1426
  /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
1183
- /* @__PURE__ */ jsx12(Text7, { bold: true, children: "Auto-approvals (up/down & space to toggle):" }),
1427
+ /* @__PURE__ */ jsx12(Text7, { bold: true, children: "Auto-approvals (up/down & <space> to toggle):" }),
1184
1428
  selectableOptions.map((option, index) => {
1185
1429
  const isSelected = index === selectedIndex && focusedArea === "status";
1186
1430
  return /* @__PURE__ */ jsx12(Box7, { children: /* @__PURE__ */ jsxs7(Text7, { color: isSelected ? "cyan" : "white", children: [
@@ -1200,7 +1444,7 @@ import { promisify } from "util";
1200
1444
  import { useCallback as useCallback3, useState as useState11 } from "react";
1201
1445
 
1202
1446
  // ink/components/BlinkingTextInput.tsx
1203
- import chalk from "chalk";
1447
+ import chalk3 from "chalk";
1204
1448
  import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
1205
1449
  import { useEffect as useEffect5, useMemo as useMemo8, useReducer, useState as useState10 } from "react";
1206
1450
  import { jsx as jsx13 } from "react/jsx-runtime";
@@ -1245,6 +1489,7 @@ var reducer = (state, action) => {
1245
1489
  };
1246
1490
  function BlinkingTextInput({
1247
1491
  isDisabled = false,
1492
+ isPassword = false,
1248
1493
  defaultValue = "",
1249
1494
  placeholder = "",
1250
1495
  suggestions = [],
@@ -1309,20 +1554,21 @@ function BlinkingTextInput({
1309
1554
  { isActive: !isDisabled }
1310
1555
  );
1311
1556
  const renderedValue = useMemo8(() => {
1557
+ const displayValue = isPassword ? "*".repeat(state.value.length) : state.value;
1312
1558
  if (isDisabled) {
1313
- const lines2 = (state.value || (placeholder ? chalk.dim(placeholder) : "")).split("\n");
1559
+ const lines2 = (displayValue || (placeholder ? chalk3.dim(placeholder) : "")).split("\n");
1314
1560
  return /* @__PURE__ */ jsx13(Box8, { flexDirection: "column", children: lines2.map((line, i) => /* @__PURE__ */ jsx13(Box8, { children: /* @__PURE__ */ jsx13(Text8, { children: line }) }, i)) });
1315
1561
  }
1316
1562
  if (state.value.length === 0) {
1317
1563
  let displayContent = "";
1318
1564
  if (placeholder && placeholder.length > 0) {
1319
- displayContent = (isCursorVisible ? chalk.inverse(placeholder[0]) : placeholder[0]) + chalk.dim(placeholder.slice(1));
1565
+ displayContent = (isCursorVisible ? chalk3.inverse(placeholder[0]) : placeholder[0]) + chalk3.dim(placeholder.slice(1));
1320
1566
  } else {
1321
- displayContent = isCursorVisible ? chalk.inverse(" ") : " ";
1567
+ displayContent = isCursorVisible ? chalk3.inverse(" ") : " ";
1322
1568
  }
1323
1569
  return /* @__PURE__ */ jsx13(Box8, { flexGrow: 1, minWidth: 1, children: /* @__PURE__ */ jsx13(Text8, { wrap: "end", children: displayContent }) });
1324
1570
  }
1325
- const lines = state.value.split("\n");
1571
+ const lines = displayValue.split("\n");
1326
1572
  const result = [];
1327
1573
  let totalOffset = 0;
1328
1574
  lines.forEach((line, lineIndex) => {
@@ -1330,7 +1576,7 @@ function BlinkingTextInput({
1330
1576
  for (let i = 0; i < line.length; i++) {
1331
1577
  const char = line[i];
1332
1578
  if (totalOffset === state.cursorOffset) {
1333
- lineContent += isCursorVisible ? chalk.inverse(char) : char;
1579
+ lineContent += isCursorVisible ? chalk3.inverse(char) : char;
1334
1580
  } else {
1335
1581
  lineContent += char;
1336
1582
  }
@@ -1338,12 +1584,12 @@ function BlinkingTextInput({
1338
1584
  }
1339
1585
  if (totalOffset === state.cursorOffset) {
1340
1586
  if (lineIndex === lines.length - 1 && suggestion) {
1341
- lineContent += (isCursorVisible ? chalk.inverse(suggestion[0]) : suggestion[0]) + chalk.dim(suggestion.slice(1));
1587
+ lineContent += (isCursorVisible ? chalk3.inverse(suggestion[0]) : suggestion[0]) + chalk3.dim(suggestion.slice(1));
1342
1588
  } else {
1343
- lineContent += isCursorVisible ? chalk.inverse(" ") : " ";
1589
+ lineContent += isCursorVisible ? chalk3.inverse(" ") : " ";
1344
1590
  }
1345
1591
  } else if (lineIndex === lines.length - 1 && suggestion) {
1346
- lineContent += chalk.dim(suggestion);
1592
+ lineContent += chalk3.dim(suggestion);
1347
1593
  }
1348
1594
  result.push(
1349
1595
  /* @__PURE__ */ jsx13(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx13(Text8, { wrap: "end", children: lineContent }) }, lineIndex)
@@ -2005,7 +2251,7 @@ function DiffApprovalView() {
2005
2251
  }
2006
2252
 
2007
2253
  // ink/configurationWizard/ConfigurationWizard.tsx
2008
- import { Box as Box18, useInput as useInput10 } from "ink";
2254
+ import { Box as Box18, useInput as useInput11 } from "ink";
2009
2255
  import { Step, Stepper } from "ink-stepper";
2010
2256
  import { useEffect as useEffect12, useState as useState15 } from "react";
2011
2257
 
@@ -2030,12 +2276,11 @@ function updateEnvKeyForProvider(provider, key) {
2030
2276
  }
2031
2277
 
2032
2278
  // ink/configurationWizard/ApiKeyStep.tsx
2033
- import { PasswordInput } from "@inkjs/ui";
2034
2279
  import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
2035
2280
  import { useStepperInput } from "ink-stepper";
2036
2281
  import { useEffect as useEffect7 } from "react";
2037
2282
  import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
2038
- function ApiKeyStep({ provider, onConfirm, onBack }) {
2283
+ function ApiKeyStep({ provider, defaultValue, onConfirm, onBack }) {
2039
2284
  const { disableNavigation, enableNavigation } = useStepperInput();
2040
2285
  useEffect7(() => {
2041
2286
  disableNavigation();
@@ -2060,18 +2305,20 @@ function ApiKeyStep({ provider, onConfirm, onBack }) {
2060
2305
  ] }),
2061
2306
  /* @__PURE__ */ jsx17(Text12, { dimColor: true, children: instructions[provider] }),
2062
2307
  /* @__PURE__ */ jsx17(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx17(
2063
- PasswordInput,
2308
+ BlinkingTextInput,
2064
2309
  {
2310
+ isPassword: true,
2311
+ defaultValue,
2065
2312
  onSubmit: (v) => {
2066
2313
  if (v === "exit") {
2067
2314
  emitToListeners("ExitUI", void 0);
2068
2315
  } else {
2069
- onConfirm(v);
2316
+ onConfirm(v || defaultValue || "");
2070
2317
  }
2071
2318
  }
2072
2319
  }
2073
2320
  ) }),
2074
- /* @__PURE__ */ jsx17(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text12, { dimColor: true, children: "Press ESC to go back" }) })
2321
+ /* @__PURE__ */ jsx17(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text12, { dimColor: true, children: "Press <esc> to go back, <enter> to proceed" }) })
2075
2322
  ] });
2076
2323
  }
2077
2324
 
@@ -2080,7 +2327,7 @@ import { Box as Box13, Text as Text13, useInput as useInput7 } from "ink";
2080
2327
  import { useStepperInput as useStepperInput2 } from "ink-stepper";
2081
2328
  import { useEffect as useEffect8 } from "react";
2082
2329
  import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
2083
- function ApiUrlStep({ provider, onConfirm, onBack }) {
2330
+ function ApiUrlStep({ provider, defaultValue, onConfirm, onBack }) {
2084
2331
  const { disableNavigation, enableNavigation } = useStepperInput2();
2085
2332
  useEffect8(() => {
2086
2333
  disableNavigation();
@@ -2106,17 +2353,18 @@ function ApiUrlStep({ provider, onConfirm, onBack }) {
2106
2353
  /* @__PURE__ */ jsx18(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx18(
2107
2354
  BlinkingTextInput,
2108
2355
  {
2356
+ defaultValue: defaultValue || "",
2109
2357
  placeholder: defaultApi[provider] || "",
2110
2358
  onSubmit: (v) => {
2111
2359
  if (v === "exit") {
2112
2360
  emitToListeners("ExitUI", void 0);
2113
2361
  } else {
2114
- onConfirm(v || defaultApi[provider] || "");
2362
+ onConfirm(v || defaultValue || defaultApi[provider] || "");
2115
2363
  }
2116
2364
  }
2117
2365
  }
2118
2366
  ) }),
2119
- /* @__PURE__ */ jsx18(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text13, { dimColor: true, children: "Press ESC to go back" }) })
2367
+ /* @__PURE__ */ jsx18(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text13, { dimColor: true, children: "Press <esc> to go back, <enter> to proceed" }) })
2120
2368
  ] });
2121
2369
  }
2122
2370
 
@@ -2168,7 +2416,13 @@ function EnvironmentSettingsStep({ onConfirm, onBack }) {
2168
2416
  label: s.label,
2169
2417
  value: s.value
2170
2418
  }));
2171
- const defaultValues = SETTINGS.map((s) => s.value);
2419
+ const defaultValues = SETTINGS.filter((s) => {
2420
+ const currentValue = process.env[s.value];
2421
+ if (currentValue === void 0) {
2422
+ return true;
2423
+ }
2424
+ return currentValue === s.defaultValue;
2425
+ }).map((s) => s.value);
2172
2426
  const handleSubmit = (values) => {
2173
2427
  for (const setting of SETTINGS) {
2174
2428
  if (values.includes(setting.value)) {
@@ -2215,11 +2469,12 @@ var compactorModelsByProvider = {
2215
2469
  import { Select } from "@inkjs/ui";
2216
2470
  import { Box as Box15, Text as Text15, useInput as useInput9 } from "ink";
2217
2471
  import { useStepperInput as useStepperInput4 } from "ink-stepper";
2218
- import { useEffect as useEffect10, useState as useState14 } from "react";
2472
+ import { useEffect as useEffect10, useMemo as useMemo11, useState as useState14 } from "react";
2219
2473
  import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
2220
2474
  function ModelSelectionStep({
2221
2475
  title,
2222
2476
  models,
2477
+ defaultValue,
2223
2478
  onConfirm,
2224
2479
  onBack
2225
2480
  }) {
@@ -2238,6 +2493,18 @@ function ModelSelectionStep({
2238
2493
  }
2239
2494
  }
2240
2495
  });
2496
+ const modelOptions = useMemo11(() => {
2497
+ const defaultIndex = models.indexOf(defaultValue);
2498
+ const sortedModels = defaultIndex >= 0 && models[defaultIndex] ? [
2499
+ models[defaultIndex],
2500
+ ...models.slice(0, defaultIndex),
2501
+ ...models.slice(defaultIndex + 1)
2502
+ ] : models;
2503
+ return [
2504
+ ...sortedModels.map((m) => ({ label: m, value: m })),
2505
+ { label: "Other...", value: "other" }
2506
+ ];
2507
+ }, [models, defaultValue]);
2241
2508
  if (isCustom) {
2242
2509
  return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
2243
2510
  /* @__PURE__ */ jsxs14(Text15, { children: [
@@ -2247,16 +2514,17 @@ function ModelSelectionStep({
2247
2514
  /* @__PURE__ */ jsx20(
2248
2515
  BlinkingTextInput,
2249
2516
  {
2517
+ defaultValue,
2250
2518
  onSubmit: (v) => {
2251
2519
  if (v === "exit") {
2252
2520
  emitToListeners("ExitUI", void 0);
2253
2521
  } else {
2254
- onConfirm(v);
2522
+ onConfirm(v || defaultValue || "");
2255
2523
  }
2256
2524
  }
2257
2525
  }
2258
2526
  ),
2259
- /* @__PURE__ */ jsx20(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text15, { dimColor: true, children: "Press ESC to go back to list" }) })
2527
+ /* @__PURE__ */ jsx20(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text15, { dimColor: true, children: "Press <esc> to go back, <enter> to select" }) })
2260
2528
  ] });
2261
2529
  }
2262
2530
  return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
@@ -2264,10 +2532,7 @@ function ModelSelectionStep({
2264
2532
  /* @__PURE__ */ jsx20(
2265
2533
  Select,
2266
2534
  {
2267
- options: [
2268
- ...models.map((m) => ({ label: m, value: m })),
2269
- { label: "Other...", value: "other" }
2270
- ],
2535
+ options: modelOptions,
2271
2536
  onChange: (v) => {
2272
2537
  if (v === "other") {
2273
2538
  setIsCustom(true);
@@ -2277,15 +2542,15 @@ function ModelSelectionStep({
2277
2542
  }
2278
2543
  }
2279
2544
  ),
2280
- /* @__PURE__ */ jsx20(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text15, { dimColor: true, children: "Press ESC to go back" }) })
2545
+ /* @__PURE__ */ jsx20(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text15, { dimColor: true, children: "Press <esc> to go back, <enter> to select" }) })
2281
2546
  ] });
2282
2547
  }
2283
2548
 
2284
2549
  // ink/configurationWizard/ProviderStep.tsx
2285
2550
  import { Select as Select2 } from "@inkjs/ui";
2286
- import { Box as Box16, Text as Text16 } from "ink";
2551
+ import { Box as Box16, Text as Text16, useInput as useInput10 } from "ink";
2287
2552
  import { useStepperInput as useStepperInput5 } from "ink-stepper";
2288
- import { useEffect as useEffect11 } from "react";
2553
+ import { useEffect as useEffect11, useMemo as useMemo12 } from "react";
2289
2554
 
2290
2555
  // ink/configurationWizard/providers.ts
2291
2556
  var providers = [
@@ -2297,21 +2562,31 @@ var providers = [
2297
2562
 
2298
2563
  // ink/configurationWizard/ProviderStep.tsx
2299
2564
  import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
2300
- function ProviderStep({ onConfirm }) {
2565
+ function ProviderStep({ defaultValue, onConfirm, onExit }) {
2301
2566
  const { disableNavigation, enableNavigation } = useStepperInput5();
2567
+ const sortedProviders = useMemo12(
2568
+ () => providers.sort((a, b) => a.label === defaultValue ? -1 : a.label.localeCompare(b.label)),
2569
+ [defaultValue]
2570
+ );
2302
2571
  useEffect11(() => {
2303
2572
  disableNavigation();
2304
2573
  return () => enableNavigation();
2305
2574
  }, [disableNavigation, enableNavigation]);
2575
+ useInput10((input, key) => {
2576
+ if (key.escape) {
2577
+ onExit();
2578
+ }
2579
+ });
2306
2580
  return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
2307
2581
  /* @__PURE__ */ jsx21(Text16, { children: "What model provider would you like to use today?" }),
2308
2582
  /* @__PURE__ */ jsx21(
2309
2583
  Select2,
2310
2584
  {
2311
- options: providers,
2585
+ options: sortedProviders,
2312
2586
  onChange: (v) => onConfirm(v)
2313
2587
  }
2314
- )
2588
+ ),
2589
+ /* @__PURE__ */ jsx21(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text16, { dimColor: true, children: "Press <esc> to cancel, <enter> to select" }) })
2315
2590
  ] });
2316
2591
  }
2317
2592
 
@@ -2355,7 +2630,9 @@ function StepperProgress({ steps, currentStep }) {
2355
2630
  // ink/configurationWizard/ConfigurationWizard.tsx
2356
2631
  import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
2357
2632
  function ConfigurationWizard({ onComplete }) {
2358
- const [provider, setProvider] = useState15("OpenAI");
2633
+ const [provider, setProvider] = useState15(
2634
+ trackedState?.model && getProvider(trackedState.model) || "OpenAI"
2635
+ );
2359
2636
  const [ollamaModels, setOllamaModels] = useState15([]);
2360
2637
  useEffect12(() => {
2361
2638
  if (provider === "Ollama") {
@@ -2366,10 +2643,13 @@ function ConfigurationWizard({ onComplete }) {
2366
2643
  });
2367
2644
  }
2368
2645
  }, [provider]);
2369
- useInput10((input, key) => {
2646
+ useInput11((input, key) => {
2370
2647
  if (key.ctrl && input === "x") {
2371
2648
  emitToListeners("ExitUI", void 0);
2372
2649
  }
2650
+ if (key.escape) {
2651
+ onComplete();
2652
+ }
2373
2653
  });
2374
2654
  const models = provider === "Ollama" && ollamaModels.length > 0 ? [.../* @__PURE__ */ new Set([...ollamaModels, ...modelsByProvider[provider]])] : modelsByProvider[provider];
2375
2655
  const compactorModels = provider === "Ollama" && ollamaModels.length > 0 ? [.../* @__PURE__ */ new Set([...ollamaModels, ...compactorModelsByProvider[provider]])] : compactorModelsByProvider[provider];
@@ -2384,16 +2664,19 @@ function ConfigurationWizard({ onComplete }) {
2384
2664
  /* @__PURE__ */ jsx23(Step, { name: "AI Provider", children: ({ goNext }) => /* @__PURE__ */ jsx23(
2385
2665
  ProviderStep,
2386
2666
  {
2667
+ defaultValue: provider,
2387
2668
  onConfirm: (p) => {
2388
2669
  setProvider(p);
2389
2670
  goNext();
2390
- }
2671
+ },
2672
+ onExit: onComplete
2391
2673
  }
2392
2674
  ) }),
2393
2675
  /* @__PURE__ */ jsx23(Step, { name: provider !== "Ollama" ? "API Key" : "API", children: ({ goNext, goBack }) => provider !== "Ollama" ? /* @__PURE__ */ jsx23(
2394
2676
  ApiKeyStep,
2395
2677
  {
2396
2678
  provider,
2679
+ defaultValue: process.env[getEnvVarForProvider(provider)] || "",
2397
2680
  onConfirm: (key) => {
2398
2681
  updateEnvKeyForProvider(provider, key);
2399
2682
  goNext();
@@ -2404,6 +2687,7 @@ function ConfigurationWizard({ onComplete }) {
2404
2687
  ApiUrlStep,
2405
2688
  {
2406
2689
  provider,
2690
+ defaultValue: process.env[getEnvVarForProvider(provider)] || "",
2407
2691
  onConfirm: (key) => {
2408
2692
  updateEnvKeyForProvider(provider, key);
2409
2693
  goNext();
@@ -2416,6 +2700,7 @@ function ConfigurationWizard({ onComplete }) {
2416
2700
  {
2417
2701
  title: "What model would you like to use?",
2418
2702
  models,
2703
+ defaultValue: trackedState?.model || "",
2419
2704
  onConfirm: (m) => {
2420
2705
  const finalModelName = provider === "Ollama" && !m.startsWith("ollama-") && !m.includes(":") ? `ollama-${m}` : m;
2421
2706
  updateEnv("HARPER_AGENT_MODEL", finalModelName);
@@ -2429,6 +2714,7 @@ function ConfigurationWizard({ onComplete }) {
2429
2714
  {
2430
2715
  title: "What model should we use for memory compaction?",
2431
2716
  models: compactorModels,
2717
+ defaultValue: trackedState?.compactionModel || "",
2432
2718
  onConfirm: (m) => {
2433
2719
  const finalModelName = provider === "Ollama" && !m.startsWith("ollama-") && !m.includes(":") ? `ollama-${m}` : m;
2434
2720
  updateEnv("HARPER_AGENT_COMPACTION_MODEL", finalModelName);
@@ -2458,6 +2744,11 @@ function bootstrapConfig() {
2458
2744
  render(/* @__PURE__ */ jsx24(MainConfig, { onComplete: resolve }));
2459
2745
  });
2460
2746
  }
2747
+ async function showConfigThenReparse() {
2748
+ await bootstrapConfig();
2749
+ parseArgs();
2750
+ bootstrapMain();
2751
+ }
2461
2752
  function MainConfig({ onComplete }) {
2462
2753
  const { exit } = useApp();
2463
2754
  useListener("ExitUI", () => exit(), [exit]);
@@ -2475,249 +2766,6 @@ function MainChat() {
2475
2766
  ] }) }) }) }) }) });
2476
2767
  }
2477
2768
 
2478
- // utils/models/deprecations.ts
2479
- import chalk2 from "chalk";
2480
- var DEPRECATION_RULES = [
2481
- // Redirect any gpt-4o variants (including dated and -mini) to gpt-5-nano
2482
- {
2483
- match: (name) => name.toLowerCase().startsWith("gpt-4o"),
2484
- replacement: "gpt-5-nano",
2485
- reason: "OpenAI gpt-4o family is deprecated in this agent"
2486
- }
2487
- ];
2488
- function getDeprecatedReplacement(modelName) {
2489
- if (!modelName) {
2490
- return null;
2491
- }
2492
- for (const rule of DEPRECATION_RULES) {
2493
- if (rule.match(modelName)) {
2494
- return { replacement: rule.replacement, rule };
2495
- }
2496
- }
2497
- return null;
2498
- }
2499
- function warnAndPersistRedirect(original, envKey, replacement, reason) {
2500
- const reasonSuffix = reason ? ` Reason: ${reason}.` : "";
2501
- console.warn(
2502
- chalk2.yellow(
2503
- `Warning: model "${original}" is deprecated and will be redirected to "${replacement}". Your environment setting (${envKey}) has been updated.${reasonSuffix}`
2504
- )
2505
- );
2506
- updateEnv(envKey, replacement);
2507
- }
2508
-
2509
- // utils/shell/cli.ts
2510
- import chalk3 from "chalk";
2511
-
2512
- // utils/package/getOwnPackageJson.ts
2513
- import { readFileSync } from "fs";
2514
- import { join } from "path";
2515
- import { fileURLToPath } from "url";
2516
- var __dirname = fileURLToPath(new URL(".", import.meta.url));
2517
- function getOwnPackageJson() {
2518
- try {
2519
- const packageContents = readFileSync(join(__dirname, "../package.json"), "utf8");
2520
- return JSON.parse(packageContents);
2521
- } catch {
2522
- return { name: "@harperfast/agent", version: "0.0.0" };
2523
- }
2524
- }
2525
-
2526
- // utils/shell/cli.ts
2527
- function isHelpRequest(args) {
2528
- const helpVariants = ["--help", "-h", "help"];
2529
- return args.some((arg) => helpVariants.includes(arg.toLowerCase()));
2530
- }
2531
- function isVersionRequest(args) {
2532
- const versionVariants = ["--version", "-v", "version"];
2533
- return args.some((arg) => versionVariants.includes(arg.toLowerCase()));
2534
- }
2535
- function handleHelp() {
2536
- console.log(`
2537
- ${chalk3.bold("harper-agent")} - AI to help you with Harper app creation and modification
2538
-
2539
- ${chalk3.bold("USAGE")}
2540
- $ harper-agent [options]
2541
- $ harper-agent [command]
2542
-
2543
- ${chalk3.bold("OPTIONS")}
2544
- -h, --help Show help information
2545
- -v, --version Show version information
2546
- -m, --model Specify the model to use (e.g., ${defaultOpenAIModel}, ${defaultAnthropicModel}, ${defaultOllamaModel})
2547
- Can also be set via HARPER_AGENT_MODEL environment variable.
2548
- For Ollama, use the ollama- prefix (e.g., ${defaultOllamaCompactionModel}).
2549
- -c, --compaction-model Specify the compaction model to use (defaults to ${defaultOpenAICompactionModel}).
2550
- Can also be set via HARPER_AGENT_COMPACTION_MODEL environment variable.
2551
- -s, --session Specify a path to a SQLite database file to persist the chat session.
2552
- Can also be set via HARPER_AGENT_SESSION environment variable.
2553
- --max-turns Specify the maximum number of turns for the agent run.
2554
- Can also be set via HARPER_AGENT_MAX_TURNS environment variable.
2555
- --max-cost Specify the maximum cost (in USD) for the agent run.
2556
- If exceeded, the agent will exit with a non-zero code.
2557
- Can also be set via HARPER_AGENT_MAX_COST environment variable.
2558
- --flex-tier Force the use of the flex service tier for lower costs but potentially
2559
- more errors under high system load.
2560
- Can also be set via HARPER_AGENT_FLEX_TIER=true environment variable.
2561
- -p, --prompt Specify a prompt to be executed autonomously until completion.
2562
-
2563
- ${chalk3.bold("COMMANDS")}
2564
- --help Show help information
2565
- --version Show version information
2566
-
2567
- ${chalk3.bold("EXAMPLES")}
2568
- $ harper-agent --help
2569
- $ harper-agent --version
2570
- $ harper-agent
2571
- `);
2572
- process.exit(0);
2573
- }
2574
- function handleVersion() {
2575
- const pkg = getOwnPackageJson();
2576
- console.log(pkg.version);
2577
- process.exit(0);
2578
- }
2579
-
2580
- // lifecycle/parseArgs.ts
2581
- function stripQuotes(str) {
2582
- if (str.startsWith('"') && str.endsWith('"') || str.startsWith("'") && str.endsWith("'")) {
2583
- return str.slice(1, -1);
2584
- }
2585
- return str;
2586
- }
2587
- function parseArgs() {
2588
- const args = process.argv.slice(2);
2589
- if (isHelpRequest(args)) {
2590
- handleHelp();
2591
- }
2592
- if (isVersionRequest(args)) {
2593
- handleVersion();
2594
- }
2595
- for (let i = 0; i < args.length; i++) {
2596
- const arg = args[i];
2597
- const flagPairs = [
2598
- ["model", ["--model", "-m", "model"]],
2599
- ["compactionModel", ["--compaction-model", "-c", "compaction-model"]],
2600
- ["sessionPath", ["--session", "-s", "session"]],
2601
- ["maxTurns", ["--max-turns"]],
2602
- ["maxCost", ["--max-cost"]],
2603
- ["rateLimitThreshold", ["--rate-limit-threshold"]],
2604
- ["prompt", ["--prompt", "-p"]]
2605
- ];
2606
- let handled = false;
2607
- for (const [key, prefixes] of flagPairs) {
2608
- for (const prefix of prefixes) {
2609
- if (arg === prefix) {
2610
- if (args[i + 1]) {
2611
- const val = stripQuotes(args[++i]);
2612
- if (key === "maxTurns" || key === "maxCost" || key === "rateLimitThreshold") {
2613
- trackedState[key] = parseFloat(val);
2614
- } else {
2615
- trackedState[key] = val;
2616
- }
2617
- }
2618
- handled = true;
2619
- break;
2620
- } else if (arg.startsWith(`${prefix}=`)) {
2621
- const val = stripQuotes(arg.slice(prefix.length + 1));
2622
- if (key === "maxTurns" || key === "maxCost" || key === "rateLimitThreshold") {
2623
- trackedState[key] = parseFloat(val);
2624
- } else {
2625
- trackedState[key] = val;
2626
- }
2627
- handled = true;
2628
- break;
2629
- }
2630
- }
2631
- if (handled) {
2632
- break;
2633
- }
2634
- }
2635
- if (handled) {
2636
- continue;
2637
- }
2638
- if (arg === "--flex-tier") {
2639
- trackedState.useFlexTier = true;
2640
- } else if (arg === "--no-monitor-rate-limits") {
2641
- trackedState.monitorRateLimits = false;
2642
- } else if (arg === "--autonomous" || arg === "-a") {
2643
- trackedState.autonomous = true;
2644
- }
2645
- }
2646
- if (!trackedState.model && process.env.HARPER_AGENT_MODEL) {
2647
- trackedState.model = process.env.HARPER_AGENT_MODEL;
2648
- }
2649
- if (!trackedState.compactionModel && process.env.HARPER_AGENT_COMPACTION_MODEL) {
2650
- trackedState.compactionModel = process.env.HARPER_AGENT_COMPACTION_MODEL;
2651
- }
2652
- if (!trackedState.sessionPath && process.env.HARPER_AGENT_SESSION) {
2653
- trackedState.sessionPath = process.env.HARPER_AGENT_SESSION;
2654
- }
2655
- if (process.env.HARPER_AGENT_MAX_TURNS) {
2656
- trackedState.maxTurns = parseFloat(process.env.HARPER_AGENT_MAX_TURNS);
2657
- }
2658
- if (process.env.HARPER_AGENT_MAX_COST) {
2659
- trackedState.maxCost = parseFloat(process.env.HARPER_AGENT_MAX_COST);
2660
- }
2661
- if (process.env.HARPER_AGENT_RATE_LIMIT_THRESHOLD) {
2662
- trackedState.rateLimitThreshold = parseFloat(process.env.HARPER_AGENT_RATE_LIMIT_THRESHOLD);
2663
- }
2664
- if (process.env.HARPER_AGENT_MONITOR_RATE_LIMITS === "false") {
2665
- trackedState.monitorRateLimits = false;
2666
- }
2667
- if (!trackedState.useFlexTier && isTrue(process.env.HARPER_AGENT_FLEX_TIER)) {
2668
- trackedState.useFlexTier = true;
2669
- }
2670
- if (isTrue(process.env.HARPER_AGENT_AUTO_APPROVE_CODE_INTERPRETER)) {
2671
- trackedState.autoApproveCodeInterpreter = true;
2672
- }
2673
- if (isTrue(process.env.HARPER_AGENT_AUTO_APPROVE_PATCHES)) {
2674
- trackedState.autoApprovePatches = true;
2675
- }
2676
- if (isTrue(process.env.HARPER_AGENT_AUTO_APPROVE_SHELL)) {
2677
- trackedState.autoApproveShell = true;
2678
- }
2679
- if (isTrue(process.env.HARPER_AGENT_AUTONOMOUS)) {
2680
- trackedState.autonomous = true;
2681
- }
2682
- if (!trackedState.model || trackedState.model === defaultModelToken) {
2683
- if (process.env.ANTHROPIC_API_KEY) {
2684
- trackedState.model = defaultAnthropicModel;
2685
- } else if (process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
2686
- trackedState.model = defaultGoogleModel;
2687
- } else if (process.env.OLLAMA_BASE_URL) {
2688
- trackedState.model = defaultOllamaModel;
2689
- } else {
2690
- trackedState.model = defaultOpenAIModel;
2691
- }
2692
- }
2693
- if (!trackedState.compactionModel || trackedState.compactionModel === defaultModelToken) {
2694
- const m = trackedState.model;
2695
- if (m.startsWith("claude-")) {
2696
- trackedState.compactionModel = defaultAnthropicCompactionModel;
2697
- } else if (m.startsWith("gemini-")) {
2698
- trackedState.compactionModel = defaultGoogleCompactionModel;
2699
- } else if (m.startsWith("ollama-")) {
2700
- trackedState.compactionModel = defaultOllamaCompactionModel;
2701
- } else {
2702
- trackedState.compactionModel = defaultOpenAICompactionModel;
2703
- }
2704
- }
2705
- if (!isOpenAIModel(trackedState.model)) {
2706
- process.env.OPENAI_AGENTS_DISABLE_TRACING = process.env.OPENAI_AGENTS_DISABLE_TRACING || "1";
2707
- }
2708
- const maybeRedirect = (current, envKey) => {
2709
- const hit = getDeprecatedReplacement(current);
2710
- if (hit) {
2711
- const { replacement, rule } = hit;
2712
- warnAndPersistRedirect(current, envKey, replacement, rule.reason);
2713
- return replacement;
2714
- }
2715
- return current;
2716
- };
2717
- trackedState.model = maybeRedirect(trackedState.model, "HARPER_AGENT_MODEL");
2718
- trackedState.compactionModel = maybeRedirect(trackedState.compactionModel, "HARPER_AGENT_COMPACTION_MODEL");
2719
- }
2720
-
2721
2769
  // utils/envLoader.ts
2722
2770
  import dotenv from "dotenv";
2723
2771
  import { existsSync } from "fs";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AgentManager
3
- } from "./chunk-SEYUVI2L.js";
3
+ } from "./chunk-HQGGUF5D.js";
4
4
  export {
5
5
  AgentManager
6
6
  };
@@ -78,41 +78,41 @@ updatedAt: Date @updatedTime
78
78
  ```
79
79
  """
80
80
  directive @table(
81
- """
82
- Explicit table name. If omitted, a sensible default derived from the
83
- type name will be used.
84
- """
85
- table: String
86
- """
87
- Logical database/namespace to place this table in.
88
- """
89
- database: String
90
- """
91
- Default time-to-live (TTL) for records in seconds. Use a positive value to
92
- enable automatic expiration; omit or set to 0 to disable.
93
- """
94
- expiration: Int
95
- """
96
- Enable auditing for create/update/delete operations.
97
- """
98
- audit: Boolean
99
- """
100
- The amount of time after expiration before a record can be evicted (defaults to zero).
101
- """
102
- eviction: Int
103
- """
104
- The interval for scanning for expired records (defaults to one quarter of the
105
- total of expiration and eviction).
106
- """
107
- scanInterval: Int
108
- """
109
- By default, all tables within a replicated database will be replicated. Transactions
110
- are replicated atomically, which may involve data across multiple tables. However,
111
- you can also configure replication for individual tables, and disable and exclude
112
- replication for specific tables in a database by setting replicate to false in the
113
- table definition.
114
- """
115
- replicate: Boolean
81
+ """
82
+ Explicit table name. If omitted, a sensible default derived from the
83
+ type name will be used.
84
+ """
85
+ table: String
86
+ """
87
+ Logical database/namespace to place this table in.
88
+ """
89
+ database: String
90
+ """
91
+ Default time-to-live (TTL) for records in seconds. Use a positive value to
92
+ enable automatic expiration; omit or set to 0 to disable.
93
+ """
94
+ expiration: Int
95
+ """
96
+ Enable auditing for create/update/delete operations.
97
+ """
98
+ audit: Boolean
99
+ """
100
+ The amount of time after expiration before a record can be evicted (defaults to zero).
101
+ """
102
+ eviction: Int
103
+ """
104
+ The interval for scanning for expired records (defaults to one quarter of the
105
+ total of expiration and eviction).
106
+ """
107
+ scanInterval: Int
108
+ """
109
+ By default, all tables within a replicated database will be replicated. Transactions
110
+ are replicated atomically, which may involve data across multiple tables. However,
111
+ you can also configure replication for individual tables, and disable and exclude
112
+ replication for specific tables in a database by setting replicate to false in the
113
+ table definition.
114
+ """
115
+ replicate: Boolean
116
116
  ) on OBJECT
117
117
 
118
118
  """
@@ -120,21 +120,21 @@ Expose the table via the REST API. When applied to a `@table` type, routes are
120
120
  generated using the type name or the provided alias.
121
121
  """
122
122
  directive @export(
123
- """
124
- Optional alias to use for REST endpoints. If omitted, the type/table name is
125
- used.
126
- """
127
- name: String
128
- """
129
- REST support is, by default, turned on for any exported resource. You may specify
130
- false to disable this automatic API support.
131
- """
132
- rest: Boolean
133
- """
134
- MQTT support is, by default, turned on for any exported resource. You may specify
135
- false to disable this automatic API support.
136
- """
137
- mqtt: Boolean
123
+ """
124
+ Optional alias to use for REST endpoints. If omitted, the type/table name is
125
+ used.
126
+ """
127
+ name: String
128
+ """
129
+ REST support is, by default, turned on for any exported resource. You may specify
130
+ false to disable this automatic API support.
131
+ """
132
+ rest: Boolean
133
+ """
134
+ MQTT support is, by default, turned on for any exported resource. You may specify
135
+ false to disable this automatic API support.
136
+ """
137
+ mqtt: Boolean
138
138
  ) on OBJECT
139
139
  """
140
140
  As a NoSQL database, HarperDB supports heterogeneous records (also referred to as
@@ -170,38 +170,38 @@ Create an index for the annotated field. Supports traditional and vector/ANN
170
170
  index types.
171
171
  """
172
172
  directive @indexed(
173
- """
174
- Optional index type, e.g. "HNSW"
175
- """
176
- type: String
177
- """
178
- Distance metric for vector indexes (e.g., "euclidean", "cosine").
179
- Ignored for non-vector index types.
180
- """
181
- distance: String
182
- """
183
- Construction effort/recall parameter (HNSW). Higher values improve recall at
184
- the cost of build time and memory.
185
- """
186
- efConstruction: Int
187
- """
188
- Maximum number of bi-directional connections per node (HNSW).
189
- Typical range: 4–64.
190
- """
191
- M: Int
192
- """
193
- Routing optimization level for search graphs (implementation-specific).
194
- """
195
- optimizeRouting: Int
196
- """
197
- Additional multiplier for graph links (implementation-specific).
198
- """
199
- mL: Int
200
- """
201
- Search-time effort/recall parameter used during construction (implementation-
202
- specific). Larger values typically yield better accuracy.
203
- """
204
- efConstructionSearch: Int
173
+ """
174
+ Optional index type, e.g. "HNSW"
175
+ """
176
+ type: String
177
+ """
178
+ Distance metric for vector indexes (e.g., "euclidean", "cosine").
179
+ Ignored for non-vector index types.
180
+ """
181
+ distance: String
182
+ """
183
+ Construction effort/recall parameter (HNSW). Higher values improve recall at
184
+ the cost of build time and memory.
185
+ """
186
+ efConstruction: Int
187
+ """
188
+ Maximum number of bi-directional connections per node (HNSW).
189
+ Typical range: 4–64.
190
+ """
191
+ M: Int
192
+ """
193
+ Routing optimization level for search graphs (implementation-specific).
194
+ """
195
+ optimizeRouting: Int
196
+ """
197
+ Additional multiplier for graph links (implementation-specific).
198
+ """
199
+ mL: Int
200
+ """
201
+ Search-time effort/recall parameter used during construction (implementation-
202
+ specific). Larger values typically yield better accuracy.
203
+ """
204
+ efConstructionSearch: Int
205
205
  ) on FIELD_DEFINITION
206
206
 
207
207
  """
@@ -209,15 +209,15 @@ Define a derived field whose value is computed from other fields.
209
209
  Useful for denormalized or presentation-friendly data.
210
210
  """
211
211
  directive @computed(
212
- """
213
- Computation expression or reference describing how to derive this field from
214
- other fields (engine-specific syntax).
215
- """
216
- from: String
217
- """
218
- Increment when the computation changes to trigger recomputation.
219
- """
220
- version: Int
212
+ """
213
+ Computation expression or reference describing how to derive this field from
214
+ other fields (engine-specific syntax).
215
+ """
216
+ from: String
217
+ """
218
+ Increment when the computation changes to trigger recomputation.
219
+ """
220
+ version: Int
221
221
  ) on FIELD_DEFINITION
222
222
  """
223
223
  Automatically sets this field to the record's creation timestamp. The server
@@ -234,12 +234,12 @@ Declares a relationship to another record or records.
234
234
  Use on fields that should resolve to related entities by ID.
235
235
  """
236
236
  directive @relationship(
237
- """
238
- Name of field in THIS table containing foreign key(s) (for one-to-many or many-to-many).
239
- """
240
- from: String
241
- """
242
- Name of field in OTHER table containing foreign key (for one-to-one or many-to-one).
243
- """
244
- to: String
237
+ """
238
+ Name of field in THIS table containing foreign key(s) (for one-to-many or many-to-many).
239
+ """
240
+ from: String
241
+ """
242
+ Name of field in OTHER table containing foreign key (for one-to-one or many-to-one).
243
+ """
244
+ to: String
245
245
  ) on FIELD_DEFINITION
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@harperfast/agent",
3
3
  "description": "AI to help you with Harper app management",
4
- "version": "0.16.14",
4
+ "version": "0.16.16",
5
5
  "main": "dist/cli.js",
6
6
  "repository": "github:HarperFast/harper-agent",
7
7
  "bugs": {
@@ -11,7 +11,7 @@
11
11
  "scripts": {
12
12
  "dev": "tsup index.ts cli.ts --format esm --clean --dts --watch --external puppeteer",
13
13
  "link": "npm run build && npm link",
14
- "build": "tsup index.ts cli.ts --format esm --clean --dts --external puppeteer && cp node_modules/harperdb/schema.graphql dist/",
14
+ "build": "tsup index.ts cli.ts --format esm --clean --dts --external puppeteer && cp node_modules/harper/schema.graphql dist/",
15
15
  "commitlint": "commitlint --edit",
16
16
  "start": "node ./dist/cli.js",
17
17
  "lint": "oxlint --format stylish .",
@@ -84,7 +84,7 @@
84
84
  "conventional-changelog-conventionalcommits": "^9.1.0",
85
85
  "dprint": "^0.53.0",
86
86
  "express": "^5.2.1",
87
- "harperdb": "^4.7.24",
87
+ "harper": "^5.0.10",
88
88
  "hono": "^4.11.9",
89
89
  "husky": "^9.1.7",
90
90
  "ink-testing-library": "^4.0.0",