agenttwin 0.3.13 → 0.3.14

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 (34) hide show
  1. package/dist/api.js +11 -1
  2. package/dist/cli.js +113 -18
  3. package/dist/dashboard/assets/next/static/chunks/app/account/password/{page-aaee6711085b485d.js → page-ebb8ab25df1b808e.js} +1 -1
  4. package/dist/dashboard/assets/next/static/chunks/app/dashboard/{layout-09cb13657f62384f.js → layout-f7cd10740b90145d.js} +1 -1
  5. package/dist/dashboard/assets/next/static/chunks/app/dashboard/{page-945c916b24f48675.js → page-a5ad912a1f481008.js} +1 -1
  6. package/dist/dashboard/assets/next/static/chunks/app/demo/{page-3cba0aab460c8677.js → page-5495d9cb9a3e1431.js} +1 -1
  7. package/dist/dashboard/assets/next/static/chunks/app/docs/[[...slug]]/{page-9f7b8dca8b973b15.js → page-9130f219b4b02112.js} +1 -1
  8. package/dist/dashboard/assets/next/static/chunks/app/enterprise/{page-4986698442bddc6b.js → page-b7e323d45eaf4952.js} +1 -1
  9. package/dist/dashboard/assets/next/static/chunks/app/{layout-09868e53e4f0541f.js → layout-ed5b209cd1b17365.js} +1 -1
  10. package/dist/dashboard/assets/next/static/chunks/app/login/page-3887863343ffce8c.js +1 -0
  11. package/dist/dashboard/assets/next/static/chunks/app/onboarding/{page-af2c4768dc34ec92.js → page-35795509a58cbc9c.js} +1 -1
  12. package/dist/dashboard/assets/next/static/chunks/app/{page-507229409812cedd.js → page-4d150b91a7a1abcc.js} +1 -1
  13. package/dist/dashboard/assets/next/static/chunks/app/pricing/page-388c0afb0ac51384.js +1 -0
  14. package/dist/dashboard/assets/next/static/chunks/app/signup/page-3887863343ffce8c.js +1 -0
  15. package/dist/dashboard/assets/next/static/chunks/app/v2/dashboard/{layout-77a57cd622171076.js → layout-1430f20bea23253f.js} +1 -1
  16. package/dist/dashboard/assets/next/static/chunks/app/v2/dashboard/page-12a8d96f5c18b411.js +1 -0
  17. package/dist/dashboard/assets/next/static/chunks/app/v2/layout-fb241571c2a60362.js +1 -0
  18. package/dist/dashboard/assets/next/static/chunks/app/v2/login/page-7ac4be578a219d6e.js +1 -0
  19. package/dist/dashboard/assets/next/static/chunks/app/v2/onboarding/{page-abfe2f36213848d7.js → page-16d9efad4103fb58.js} +1 -1
  20. package/dist/dashboard/assets/next/static/chunks/app/v2/{page-df6a34eff716d18e.js → page-1d465878abb57f0f.js} +1 -1
  21. package/dist/dashboard/assets/next/static/chunks/app/v2/signup/page-7ac4be578a219d6e.js +1 -0
  22. package/dist/dashboard/assets/next/static/chunks/{webpack-44457f45df749a89.js → webpack-9ed8651d8c2c40a2.js} +1 -1
  23. package/dist/dashboard/index.html +2 -2
  24. package/dist/gateway.js +11 -1
  25. package/package.json +1 -1
  26. package/dist/dashboard/assets/next/static/chunks/app/login/page-2e29d4b17645c34c.js +0 -1
  27. package/dist/dashboard/assets/next/static/chunks/app/pricing/page-c27282cd7bfb0fcf.js +0 -1
  28. package/dist/dashboard/assets/next/static/chunks/app/signup/page-2e29d4b17645c34c.js +0 -1
  29. package/dist/dashboard/assets/next/static/chunks/app/v2/dashboard/page-df34bcef0394d10d.js +0 -1
  30. package/dist/dashboard/assets/next/static/chunks/app/v2/layout-d1d715b5b2dae3cd.js +0 -1
  31. package/dist/dashboard/assets/next/static/chunks/app/v2/login/page-4f60d050bf954194.js +0 -1
  32. package/dist/dashboard/assets/next/static/chunks/app/v2/signup/page-4f60d050bf954194.js +0 -1
  33. /package/dist/dashboard/assets/next/static/{BbTZs0rKnsmj45peSnlwJ → O8JeB5KAl7-h1hCNIyUY7}/_buildManifest.js +0 -0
  34. /package/dist/dashboard/assets/next/static/{BbTZs0rKnsmj45peSnlwJ → O8JeB5KAl7-h1hCNIyUY7}/_ssgManifest.js +0 -0
package/dist/api.js CHANGED
@@ -4290,6 +4290,7 @@ async function startGateway(opts) {
4290
4290
  const passkeyChallenges = {};
4291
4291
  const devices = /* @__PURE__ */ new Map();
4292
4292
  let hashing = 0;
4293
+ let localOnboardingUntil = 0;
4293
4294
  const dummyPassword = randomBytes6(16).toString("hex") + ":" + randomBytes6(64).toString("hex");
4294
4295
  const server = createServer2(async (req, res) => {
4295
4296
  try {
@@ -4356,7 +4357,7 @@ async function startGateway(opts) {
4356
4357
  };
4357
4358
  const profile = (a) => ({ accountId: a.id, email: a.identity?.email, name: a.identity?.name ?? a.label, workspace: a.label, organization: a.organization, workspaceProfile: a.workspaceProfile, passwordEnabled: !!a.identity?.passwordHash, passwordSetupAllowed: !a.identity?.passwordHash && !!a.externalIdentities?.some((i) => i.provider === "google") });
4358
4359
  if (path2 === "/v1/dev/workspace" && req.method === "GET" && opts.localDevelopment && ["127.0.0.1", "localhost"].includes(opts.host ?? "") && verificationUrl === "http://localhost:3000/onboarding/") {
4359
- send(res, 200, { schema: "agenttwin/local-workspace-v1", dashboard: verificationUrl });
4360
+ send(res, 200, { schema: "agenttwin/local-workspace-v1", dashboard: verificationUrl, onboarding: localOnboardingUntil > Date.now() });
4360
4361
  return;
4361
4362
  }
4362
4363
  if (path2 === "/v1/auth/providers" && req.method === "GET") {
@@ -4859,6 +4860,15 @@ async function startGateway(opts) {
4859
4860
  send(res, 401, { error: "unauthorized" });
4860
4861
  return;
4861
4862
  }
4863
+ if (path2 === "/v1/dev/workspace" && req.method === "POST" && opts.localDevelopment && ["127.0.0.1", "localhost"].includes(opts.host ?? "") && verificationUrl === "http://localhost:3000/onboarding/") {
4864
+ if (token || !session || origin !== "http://localhost:3000") {
4865
+ send(res, 403, { error: "browser_session_required" });
4866
+ return;
4867
+ }
4868
+ localOnboardingUntil = Date.now() + 10 * 6e4;
4869
+ send(res, 200, { waiting: true });
4870
+ return;
4871
+ }
4862
4872
  if (path2 === "/v1/auth/password" && req.method === "POST") {
4863
4873
  if (token || !session || !account.identity || !origin || !allowedOrigins.has(origin)) {
4864
4874
  send(res, 403, { error: "browser_session_required" });
package/dist/cli.js CHANGED
@@ -1929,7 +1929,7 @@ import { join as join34 } from "path";
1929
1929
  // package.json
1930
1930
  var package_default = {
1931
1931
  name: "agenttwin",
1932
- version: "0.3.13",
1932
+ version: "0.3.14",
1933
1933
  description: "Give your agent a test world before it touches the real one.",
1934
1934
  keywords: [
1935
1935
  "agent",
@@ -2055,7 +2055,7 @@ async function runSync(cwd) {
2055
2055
  if (!response.ok) throw new Error(result.error || "Discovery sync failed: " + response.status);
2056
2056
  if (git) await writeFile5(join8(cwd, ".agenttwin/git.json"), JSON.stringify(git) + "\n", { mode: 384 });
2057
2057
  const receipts = await syncReceipts(cwd, base, token);
2058
- return { receipts, synced: true, tools: payload.tools.length, workflows: payload.workflows.length, dashboard: "https://agenttwin.si/dashboard/", uploaded: "discovery, Git metadata and run evidence; no application source or credentials" };
2058
+ return { receipts, synced: true, tools: payload.tools.length, workflows: payload.workflows.length, dashboard: base === "http://localhost:8080" ? "http://localhost:3000/dashboard/" : "https://agenttwin.si/dashboard/", uploaded: "discovery, Git metadata and run evidence; no application source or credentials" };
2059
2059
  }
2060
2060
 
2061
2061
  // src/commands/prepare.ts
@@ -9134,6 +9134,7 @@ async function runInit(opts) {
9134
9134
  if (opts.agent && (opts.dryRun || opts.json)) throw new Error("A coding session requires a writing, interactive init (omit --dry-run and --json).");
9135
9135
  setQuiet(opts.json);
9136
9136
  const interactive = !opts.json && !opts.yes && !opts.dryRun && (opts.interactive === true || !opts.json && process.stdin.isTTY === true && process.stdout.isTTY === true);
9137
+ const quickInit = interactive && opts.finishAfterSync === true;
9137
9138
  const log = (message) => {
9138
9139
  if (!message.startsWith("inspect ")) process.stderr.write(`${message}
9139
9140
  `);
@@ -9159,7 +9160,12 @@ async function runInit(opts) {
9159
9160
  inventory = applyInventoryAnswers(inventory, Object.fromEntries(excludedTools.map((t) => [`tool.exclude:${t.id}`, false])));
9160
9161
  if (!opts.json) {
9161
9162
  info("");
9162
- info(renderOverview(inventory));
9163
+ if (quickInit) {
9164
+ const integrations = inventory.tools.filter((tool2) => tool2.category === "dependency").length;
9165
+ const gaps = inventory.coverage.sources.filter((source) => source.status !== "ok" && source.status !== "skipped");
9166
+ info(`Detected ${inventory.services.length} applications, ${integrations} referenced integrations and ${inventory.workflows.length} code paths.`);
9167
+ if (gaps.length) warn(`Scan limitations: ${gaps.map((source) => `${source.id}=${source.status}`).join(", ")}`);
9168
+ } else info(renderOverview(inventory));
9163
9169
  info("");
9164
9170
  }
9165
9171
  const decisions = (await readDecisions(opts.cwd))?.items ?? [];
@@ -9170,14 +9176,14 @@ async function runInit(opts) {
9170
9176
  const { parseAnswersFile: parseAnswersFile2 } = await Promise.resolve().then(() => (init_answers(), answers_exports));
9171
9177
  answers = parseAnswersFile2(readFileSync2(opts.answers, "utf8"));
9172
9178
  }
9173
- if (interactive && questions.length > 0) {
9179
+ if (interactive && !quickInit && questions.length > 0) {
9174
9180
  const asked = await askQuestions(questions);
9175
9181
  answers = { ...answers, ...asked.answers };
9176
9182
  }
9177
9183
  answers = { ...stored, ...defaultAnswers(questions), ...answers };
9178
9184
  const finalInventory = applyInventoryAnswers(inventory, answers);
9179
9185
  const plan = buildPlan(finalInventory);
9180
- if (interactive) {
9186
+ if (interactive && !quickInit) {
9181
9187
  const proceed = await confirm(`Write ${CONFIG_FILENAME}, ENVIRONMENT.md and REPLICATION.md?`);
9182
9188
  if (!proceed) {
9183
9189
  info("Aborted \u2014 nothing written.");
@@ -9203,16 +9209,18 @@ async function runInit(opts) {
9203
9209
  await writeConfig(opts.cwd, config, { force: opts.force });
9204
9210
  await writeFile20(join25(opts.cwd, "ENVIRONMENT.md"), renderEnvironment(finalInventory), "utf8");
9205
9211
  await writeFile20(join25(opts.cwd, "REPLICATION.md"), renderReplication(finalInventory, plan), "utf8");
9206
- reportPath = await writeBrowserReport(opts.cwd, finalInventory, plan);
9207
- dashboardPath = await writeDashboard(opts.cwd, finalInventory);
9212
+ if (!quickInit) {
9213
+ reportPath = await writeBrowserReport(opts.cwd, finalInventory, plan);
9214
+ dashboardPath = await writeDashboard(opts.cwd, finalInventory);
9215
+ }
9208
9216
  wrote = true;
9209
9217
  if (!opts.json) {
9210
9218
  info("");
9211
9219
  ok2(`Wrote ${CONFIG_FILENAME}`);
9212
9220
  ok2("Wrote ENVIRONMENT.md");
9213
9221
  ok2("Wrote REPLICATION.md");
9214
- ok2(`Browser report: ${reportPath}`);
9215
- ok2(`Dashboard: ${dashboardPath}`);
9222
+ if (reportPath) ok2(`Browser report: ${reportPath}`);
9223
+ if (dashboardPath) ok2(`Dashboard: ${dashboardPath}`);
9216
9224
  }
9217
9225
  } else if (!opts.json) {
9218
9226
  warn("Dry run \u2014 nothing written.");
@@ -9348,6 +9356,52 @@ async function saveExplorationRegression(cwd, explorationId, trialIndex, id) {
9348
9356
 
9349
9357
  // src/commands/control.ts
9350
9358
  init_repair_evidence();
9359
+
9360
+ // src/inventory/workflow-picker.ts
9361
+ function workflowRoute(workflow) {
9362
+ const match = (workflow.entrypoint ?? workflow.title).match(/(?:#|^)route:([A-Z]+):(.+)@\d+$/);
9363
+ return match ? { method: match[1], path: match[2] } : void 0;
9364
+ }
9365
+ function workflowLabel(workflow) {
9366
+ const route = workflowRoute(workflow);
9367
+ return route ? `${route.method} ${route.path}` : workflow.title;
9368
+ }
9369
+ function workflowArea(workflow) {
9370
+ const route = workflowRoute(workflow);
9371
+ if (!route) return void 0;
9372
+ const path2 = route.path.toLowerCase();
9373
+ if (/\/(?:internal|admin)(?:\/|$)/.test(path2) || /\/(?:healthz?|readyz|status|evals)(?:\/|$)/.test(path2)) return "Internal and maintenance";
9374
+ if (/\/(?:mail|email|gmail)(?:\/|$)/.test(path2)) return "Email";
9375
+ if (/\/(?:calendar|meetings?|events?)(?:\/|$)/.test(path2)) return "Calendar";
9376
+ if (/\/(?:billing|payments?|subscriptions?|checkout)(?:\/|$)/.test(path2)) return "Payments and billing";
9377
+ if (/\/(?:auth|login|logout|signup|account|me)(?:\/|$)/.test(path2)) return "Accounts and sign-in";
9378
+ if (/\/(?:chat|messages?|conversations?)(?:\/|$)/.test(path2)) return "Chat and messages";
9379
+ if (/\/(?:tasks?|work|reminders?)(?:\/|$)/.test(path2)) return "Tasks and reminders";
9380
+ return "Other application endpoints";
9381
+ }
9382
+ function workflowAreas(workflows) {
9383
+ const grouped = /* @__PURE__ */ new Map();
9384
+ for (const workflow of workflows) {
9385
+ const area = workflowArea(workflow);
9386
+ if (area) grouped.set(area, [...grouped.get(area) ?? [], workflow]);
9387
+ }
9388
+ return [...grouped.entries()].sort(([a], [b]) => Number(a === "Internal and maintenance") - Number(b === "Internal and maintenance") || a.localeCompare(b));
9389
+ }
9390
+
9391
+ // src/runtime/local-workspace.ts
9392
+ async function detectLocalWorkspace(request = fetch) {
9393
+ try {
9394
+ const response = await request("http://localhost:8080/v1/dev/workspace", { redirect: "error", signal: AbortSignal.timeout(700) });
9395
+ if (!response.ok) return null;
9396
+ const data = await response.json();
9397
+ if (data.schema !== "agenttwin/local-workspace-v1" || data.dashboard !== "http://localhost:3000/onboarding/") return null;
9398
+ return { api: "http://localhost:8080", dashboard: data.dashboard, onboarding: data.onboarding === true };
9399
+ } catch {
9400
+ return null;
9401
+ }
9402
+ }
9403
+
9404
+ // src/commands/control.ts
9351
9405
  var CONTROL_ACTIONS = [
9352
9406
  "Review service coverage and provider contracts",
9353
9407
  "Prepare or select your reviewed workflow world",
@@ -9377,6 +9431,11 @@ async function runControl(opts) {
9377
9431
  const wrote = await runInit({ ...opts, interactive, controller: true });
9378
9432
  if (!interactive || !wrote) return;
9379
9433
  const state = await readState(opts.cwd);
9434
+ const originalApi = process.env.AGENTTWIN_API_URL;
9435
+ if (!originalApi && !process.env.AGENTTWIN_TOKEN) {
9436
+ const local = await detectLocalWorkspace();
9437
+ if (local?.onboarding) process.env.AGENTTWIN_API_URL = local.api;
9438
+ }
9380
9439
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
9381
9440
  const log = (message) => process.stdout.write(message + "\n");
9382
9441
  const ask = async (prompt) => (await rl.question(prompt + " ")).trim();
@@ -9400,9 +9459,32 @@ async function runControl(opts) {
9400
9459
  log("No workflow candidates found. Refresh discovery in Advanced options, or load an existing test file.");
9401
9460
  return;
9402
9461
  }
9403
- log(`${workflows.length} workflow candidates found. These are code paths, not tested workflows yet.`);
9404
- const query = (await ask("Find a workflow (for example mail, calendar or billing; Enter shows all):")).toLowerCase();
9405
- const matches2 = workflows.filter((w) => `${w.title} ${w.entrypoint ?? ""}`.toLowerCase().includes(query));
9462
+ const areas = workflowAreas(workflows);
9463
+ let matches2 = workflows;
9464
+ if (areas.length) {
9465
+ log("\nWhich part of your application do you want to test?");
9466
+ areas.forEach(([name, items], i) => log(` ${i + 1}. ${name} (${items.length} endpoints)`));
9467
+ log(" a. All code paths, including helpers");
9468
+ log(" 0. Back");
9469
+ const area = await ask("Choose an area, or type a search:");
9470
+ if (!area || area === "0") return;
9471
+ const selectedArea = /^\d+$/.test(area) ? areas[Number(area) - 1] : void 0;
9472
+ if (selectedArea) {
9473
+ matches2 = selectedArea[1];
9474
+ log(`
9475
+ ${selectedArea[0]} \u2014 choose an endpoint to prepare. These have not been tested yet.`);
9476
+ } else if (area.toLowerCase() !== "a") {
9477
+ if (/^\d+$/.test(area)) {
9478
+ log("Choose a listed area.");
9479
+ return;
9480
+ }
9481
+ matches2 = workflows.filter((w) => `${w.title} ${w.entrypoint ?? ""}`.toLowerCase().includes(area.toLowerCase()));
9482
+ }
9483
+ } else {
9484
+ log(`${workflows.length} code paths found. These have not been tested yet.`);
9485
+ const query = (await ask("Find a workflow (for example mail, calendar or billing; Enter shows all):")).toLowerCase();
9486
+ matches2 = workflows.filter((w) => `${w.title} ${w.entrypoint ?? ""}`.toLowerCase().includes(query));
9487
+ }
9406
9488
  if (!matches2.length) {
9407
9489
  log("No matching workflows. Try another search.");
9408
9490
  return;
@@ -9410,7 +9492,7 @@ async function runControl(opts) {
9410
9492
  let offset = 0;
9411
9493
  while (true) {
9412
9494
  const page2 = matches2.slice(offset, offset + 10);
9413
- page2.forEach((w, i) => log(` ${i + 1}. ${w.title}${w.entrypoint ? ` \xB7 ${w.entrypoint}` : ""}`));
9495
+ page2.forEach((w, i) => log(` ${i + 1}. ${workflowLabel(w)}`));
9414
9496
  log(`Showing ${offset + 1}\u2013${offset + page2.length} of ${matches2.length}. n: next page \xB7 p: previous page \xB7 0: back`);
9415
9497
  const selected = await ask("Choose a workflow [0]:");
9416
9498
  if (!selected || selected === "0") return;
@@ -9428,12 +9510,13 @@ async function runControl(opts) {
9428
9510
  continue;
9429
9511
  }
9430
9512
  state.workflowId = workflow.id;
9431
- state.workflowTitle = workflow.title;
9513
+ state.workflowTitle = workflowLabel(workflow);
9432
9514
  delete state.world;
9433
9515
  delete state.exploration;
9434
9516
  delete state.receipt;
9435
9517
  await save();
9436
- log(`Selected: ${workflow.title}`);
9518
+ log(`Selected: ${workflowLabel(workflow)}`);
9519
+ if (workflow.entrypoint) log(`Source: ${workflow.entrypoint}`);
9437
9520
  log("Next: prepare its test. AgentTwin cannot yet turn every detected code path into a runnable test automatically.");
9438
9521
  log("Give your coding agent this request:");
9439
9522
  log(`Read .agenttwin/AGENT-TASK.md and .agenttwin/inventory.json. Prepare workflow ${JSON.stringify(workflow.id)} (${JSON.stringify(workflow.title)}) as agenttwin.world.json, with bundled application files, supported service operations, synthetic records and reviewed expected outcomes. Report unsupported dependencies; do not replace the application with a demo.`);
@@ -9444,8 +9527,17 @@ async function runControl(opts) {
9444
9527
  try {
9445
9528
  try {
9446
9529
  await connectAndShare();
9530
+ if (opts.finishAfterSync) {
9531
+ log("Setup complete. Project synced; your onboarding page updates automatically. Continue in your browser.");
9532
+ log("For terminal testing later, run npx agenttwin.");
9533
+ return;
9534
+ }
9447
9535
  } catch (error) {
9448
- log(`Connection stopped: ${error instanceof Error ? error.message : String(error)}. Local discovery is saved. Retry Connect project in Advanced options.`);
9536
+ log(`Connection stopped: ${error instanceof Error ? error.message : String(error)}. Local discovery is saved. Run npx agenttwin init to retry.`);
9537
+ if (opts.finishAfterSync) {
9538
+ process.exitCode = 1;
9539
+ return;
9540
+ }
9449
9541
  }
9450
9542
  while (true) {
9451
9543
  log(`
@@ -9610,6 +9702,8 @@ AgentTwin \xB7 ${basename4(opts.cwd)}`);
9610
9702
  }
9611
9703
  } finally {
9612
9704
  rl.close();
9705
+ if (originalApi === void 0) delete process.env.AGENTTWIN_API_URL;
9706
+ else process.env.AGENTTWIN_API_URL = originalApi;
9613
9707
  }
9614
9708
  }
9615
9709
 
@@ -10936,7 +11030,7 @@ function helpText() {
10936
11030
  ` ${"services".padEnd(12)}list | coverage | confirm --host HOST --decision include|exclude`,
10937
11031
  ` ${"example".padEnd(12)}Write an editable multi-service workflow (--out directory)`,
10938
11032
  ` ${"sync".padEnd(12)}Sync discovery, Git metadata and CLI test results to your dashboard`,
10939
- ` ${"init".padEnd(12)}Discover and open the guided repository control center`,
11033
+ ` ${"init".padEnd(12)}Discover, connect and sync; continue in your browser`,
10940
11034
  ` ${"refresh".padEnd(12)}Update discovery without executing application code`,
10941
11035
  ` ${"discover".padEnd(12)}Build the company inventory (writes .agenttwin/inventory.json)`,
10942
11036
  ` ${"decide".padEnd(12)}Apply structured decisions (--file or --stdin)`,
@@ -11249,7 +11343,8 @@ ${result.uploaded}`);
11249
11343
  agent: str2("agent"),
11250
11344
  sync: flag("sync"),
11251
11345
  exclude: arr("exclude"),
11252
- controller: true
11346
+ controller: true,
11347
+ finishAfterSync: positionals[0] === "init"
11253
11348
  });
11254
11349
  return;
11255
11350
  case "logout": {
@@ -1 +1 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9842],{6419:(e,a,s)=>{"use strict";s.d(a,{default:()=>o});var n=s(1778),t=s(5226),r=s(650);function o(){let[e,a]=(0,t.useState)(null),[s,o]=(0,t.useState)(!0),[i,l]=(0,t.useState)(""),[d,c]=(0,t.useState)(""),[h,u]=(0,t.useState)(!1),[p,w]=(0,t.useState)(""),[g,m]=(0,t.useState)(!1),[f,y]=(0,t.useState)("/login/");async function j(e){if(e.preventDefault(),!h){if(w(""),i!==d)return void w("The passwords do not match.");u(!0);try{let e=await fetch(r.n+"/v1/auth/password",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:i}),signal:AbortSignal.timeout(2e4)}),s=await e.json();if(!e.ok)throw Error(s.error||"Could not create your password.");a(s.user),l(""),c(""),m(!0)}catch(e){w(e instanceof TypeError?"Could not connect to AgentTwin. Please try again.":e instanceof Error?e.message:"Could not create your password.")}finally{u(!1)}}}return(0,t.useEffect)(()=>{let e=new AbortController,s=["localhost","127.0.0.1"].includes(location.hostname)&&"https://api.agenttwin.si"===r.n;return s&&y("https://agenttwin.si/login/"),fetch(r.n+"/v1/auth/me",{credentials:"include",signal:e.signal,cache:"no-store"}).then(async e=>{var s;if(!e.ok)throw Error("Sign in with Google, then open Settings → Email and password.");let n=await e.json();if(!(null==(s=n.user)?void 0:s.email))throw Error("Could not load your account. Please sign in again.");a(n.user)}).catch(a=>{e.signal.aborted||w(a instanceof TypeError?s?"This local preview cannot connect to production sign-in. Open agenttwin.si to manage your password.":"Could not connect to AgentTwin. Please try again.":a instanceof Error?a.message:"Could not load your account.")}).finally(()=>{e.signal.aborted||o(!1)}),()=>e.abort()},[]),(0,n.jsxs)("main",{className:"auth-page auth-entry vercel-auth vercel-entry",children:[(0,n.jsxs)("header",{className:"auth-header",children:[(0,n.jsx)("a",{className:"auth-brand",href:"/","aria-label":"AgentTwin home",children:(0,n.jsx)("img",{src:"assets/logo/mark-twin-rings.svg",width:"26",height:"26",alt:""})}),(0,n.jsx)("a",{className:"auth-header-link",href:"/dashboard/#settings",children:"Back to settings"})]}),(0,n.jsxs)("section",{className:"auth-card auth-entry-card","aria-labelledby":"password-title",children:[(0,n.jsx)("h1",{id:"password-title",children:"Email and password"}),s&&(0,n.jsx)("p",{role:"status",children:"Loading your sign-in methods…"}),p&&(0,n.jsx)("p",{role:"alert",children:p}),g?(0,n.jsxs)("p",{role:"status",children:["Password created. You can now sign in with ",null==e?void 0:e.email," and your password, or continue with Google. Your workspace is the same."]}):(null==e?void 0:e.passwordEnabled)?(0,n.jsxs)("p",{children:["Email and password sign-in is already enabled for ",e.email,"."]}):(null==e?void 0:e.passwordSetupAllowed)?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["Create an AgentTwin password for ",e.email,". Google sign-in will keep working."]}),(0,n.jsx)("p",{children:"For security, sign in with Google within the last 10 minutes before saving."}),(0,n.jsxs)("form",{onSubmit:j,"aria-busy":h,children:[(0,n.jsx)("input",{type:"text",name:"username",autoComplete:"username",value:e.email,readOnly:!0,hidden:!0}),(0,n.jsxs)("label",{htmlFor:"new-password",children:["New password",(0,n.jsx)("input",{id:"new-password",type:"password",autoComplete:"new-password",minLength:12,maxLength:128,required:!0,value:i,onChange:e=>l(e.target.value),"aria-describedby":"password-guidance"})]}),(0,n.jsx)("small",{id:"password-guidance",children:"Use 12–128 characters. This is a new AgentTwin password, separate from your Google password."}),(0,n.jsxs)("label",{htmlFor:"confirm-password",children:["Confirm password",(0,n.jsx)("input",{id:"confirm-password",type:"password",autoComplete:"new-password",minLength:12,maxLength:128,required:!0,value:d,onChange:e=>c(e.target.value)})]}),(0,n.jsx)("button",{className:"auth-primary",type:"submit",disabled:h,children:h?"Saving…":"Create password"})]})]}):e&&(0,n.jsx)("p",{children:"Password setup is available for accounts created with Google."}),!s&&!g&&!(null==e?void 0:e.passwordEnabled)&&(0,n.jsx)("p",{children:(0,n.jsx)("a",{href:f,children:"Sign in with Google again →"})})]}),(0,n.jsx)("footer",{className:"auth-footer",children:(0,n.jsx)("a",{href:"/dashboard/#settings",children:"Back to settings"})})]})}},8911:(e,a,s)=>{Promise.resolve().then(s.bind(s,6419))}},e=>{e.O(0,[1839,650,7903,4816,7358],()=>e(e.s=8911)),_N_E=e.O()}]);
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9842],{6419:(e,a,s)=>{"use strict";s.d(a,{default:()=>o});var n=s(1778),t=s(5226),r=s(650);function o(){let[e,a]=(0,t.useState)(null),[s,o]=(0,t.useState)(!0),[i,l]=(0,t.useState)(""),[d,c]=(0,t.useState)(""),[h,u]=(0,t.useState)(!1),[p,w]=(0,t.useState)(""),[g,m]=(0,t.useState)(!1),[f,y]=(0,t.useState)("/login/");async function j(e){if(e.preventDefault(),!h){if(w(""),i!==d)return void w("The passwords do not match.");u(!0);try{let e=await fetch(r.n+"/v1/auth/password",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:i}),signal:AbortSignal.timeout(2e4)}),s=await e.json();if(!e.ok)throw Error(s.error||"Could not create your password.");a(s.user),l(""),c(""),m(!0)}catch(e){w(e instanceof TypeError?"Could not connect to AgentTwin. Please try again.":e instanceof Error?e.message:"Could not create your password.")}finally{u(!1)}}}return(0,t.useEffect)(()=>{let e=new AbortController,s=["localhost","127.0.0.1"].includes(location.hostname)&&"https://api.agenttwin.si"===r.n;return s&&y("https://agenttwin.si/login/"),fetch(r.n+"/v1/auth/me",{credentials:"include",signal:e.signal,cache:"no-store"}).then(async e=>{var s;if(!e.ok)throw Error("Sign in with Google, then open Settings → Email and password.");let n=await e.json();if(!(null==(s=n.user)?void 0:s.email))throw Error("Could not load your account. Please sign in again.");a(n.user)}).catch(a=>{e.signal.aborted||w(a instanceof TypeError?s?"This local preview cannot connect to production sign-in. Open agenttwin.si to manage your password.":"Could not connect to AgentTwin. Please try again.":a instanceof Error?a.message:"Could not load your account.")}).finally(()=>{e.signal.aborted||o(!1)}),()=>e.abort()},[]),(0,n.jsxs)("main",{className:"auth-page auth-entry vercel-auth vercel-entry",children:[(0,n.jsxs)("header",{className:"auth-header",children:[(0,n.jsx)("a",{className:"auth-brand",href:"/","aria-label":"AgentTwin home",children:(0,n.jsx)("img",{src:"assets/logo/mark-twin-rings.svg",width:"26",height:"26",alt:""})}),(0,n.jsx)("a",{className:"auth-header-link",href:"/dashboard/#settings",children:"Back to settings"})]}),(0,n.jsxs)("section",{className:"auth-card auth-entry-card","aria-labelledby":"password-title",children:[(0,n.jsx)("h1",{id:"password-title",children:"Email and password"}),s&&(0,n.jsx)("p",{role:"status",children:"Loading your sign-in methods…"}),p&&(0,n.jsx)("p",{role:"alert",children:p}),g?(0,n.jsxs)("p",{role:"status",children:["Password created. You can now sign in with ",null==e?void 0:e.email," and your password, or continue with Google. Your workspace is the same."]}):(null==e?void 0:e.passwordEnabled)?(0,n.jsxs)("p",{children:["Email and password sign-in is already enabled for ",e.email,"."]}):(null==e?void 0:e.passwordSetupAllowed)?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["Create an AgentTwin password for ",e.email,". Google sign-in will keep working."]}),(0,n.jsx)("p",{children:"For security, sign in with Google within the last 10 minutes before saving."}),(0,n.jsxs)("form",{onSubmit:j,"aria-busy":h,children:[(0,n.jsx)("input",{type:"text",name:"username",autoComplete:"username",value:e.email,readOnly:!0,hidden:!0}),(0,n.jsxs)("label",{htmlFor:"new-password",children:["New password",(0,n.jsx)("input",{id:"new-password",type:"password",autoComplete:"new-password",minLength:12,maxLength:128,required:!0,value:i,onChange:e=>l(e.target.value),"aria-describedby":"password-guidance"})]}),(0,n.jsx)("small",{id:"password-guidance",children:"Use 12–128 characters. This is a new AgentTwin password, separate from your Google password."}),(0,n.jsxs)("label",{htmlFor:"confirm-password",children:["Confirm password",(0,n.jsx)("input",{id:"confirm-password",type:"password",autoComplete:"new-password",minLength:12,maxLength:128,required:!0,value:d,onChange:e=>c(e.target.value)})]}),(0,n.jsx)("button",{className:"auth-primary",type:"submit",disabled:h,children:h?"Saving…":"Create password"})]})]}):e&&(0,n.jsx)("p",{children:"Password setup is available for accounts created with Google."}),!s&&!g&&!(null==e?void 0:e.passwordEnabled)&&(0,n.jsx)("p",{children:(0,n.jsx)("a",{href:f,children:"Sign in with Google again →"})})]}),(0,n.jsx)("footer",{className:"auth-footer",children:(0,n.jsx)("a",{href:"/dashboard/#settings",children:"Back to settings"})})]})}},7461:(e,a,s)=>{Promise.resolve().then(s.bind(s,6419))}},e=>{e.O(0,[1839,650,7903,4816,7358],()=>e(e.s=7461)),_N_E=e.O()}]);
@@ -1 +1 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1954],{1059:()=>{},1125:()=>{},1127:()=>{},1470:()=>{},1685:()=>{},2569:()=>{},2908:()=>{},3597:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,1059,23)),Promise.resolve().then(n.t.bind(n,2569,23)),Promise.resolve().then(n.t.bind(n,1470,23)),Promise.resolve().then(n.t.bind(n,8866,23)),Promise.resolve().then(n.t.bind(n,1685,23)),Promise.resolve().then(n.t.bind(n,1127,23)),Promise.resolve().then(n.t.bind(n,2908,23)),Promise.resolve().then(n.t.bind(n,1125,23))},8866:()=>{}},e=>{e.O(0,[8605,4469,508,7903,4816,7358],()=>e(e.s=3597)),_N_E=e.O()}]);
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1954],{1059:()=>{},1125:()=>{},1127:()=>{},1470:()=>{},1685:()=>{},2569:()=>{},2908:()=>{},4389:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,1059,23)),Promise.resolve().then(n.t.bind(n,2569,23)),Promise.resolve().then(n.t.bind(n,1470,23)),Promise.resolve().then(n.t.bind(n,8866,23)),Promise.resolve().then(n.t.bind(n,1685,23)),Promise.resolve().then(n.t.bind(n,1127,23)),Promise.resolve().then(n.t.bind(n,2908,23)),Promise.resolve().then(n.t.bind(n,1125,23))},8866:()=>{}},e=>{e.O(0,[8605,4469,508,7903,4816,7358],()=>e(e.s=4389)),_N_E=e.O()}]);