stagent 0.1.10 → 0.1.12

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 (112) hide show
  1. package/README.md +58 -27
  2. package/package.json +3 -3
  3. package/src/__tests__/e2e/blueprint.test.ts +63 -0
  4. package/src/__tests__/e2e/cross-runtime.test.ts +77 -0
  5. package/src/__tests__/e2e/helpers.ts +286 -0
  6. package/src/__tests__/e2e/parallel-workflow.test.ts +120 -0
  7. package/src/__tests__/e2e/sequence-workflow.test.ts +109 -0
  8. package/src/__tests__/e2e/setup.ts +156 -0
  9. package/src/__tests__/e2e/single-task.test.ts +170 -0
  10. package/src/app/api/command-palette/recent/route.ts +41 -18
  11. package/src/app/api/context/batch/route.ts +44 -0
  12. package/src/app/api/permissions/presets/route.ts +80 -0
  13. package/src/app/api/playbook/status/route.ts +15 -0
  14. package/src/app/api/profiles/route.ts +23 -21
  15. package/src/app/api/settings/pricing/route.ts +15 -0
  16. package/src/app/costs/page.tsx +53 -43
  17. package/src/app/globals.css +0 -5
  18. package/src/app/playbook/[slug]/page.tsx +76 -0
  19. package/src/app/playbook/page.tsx +54 -0
  20. package/src/app/profiles/page.tsx +7 -4
  21. package/src/app/settings/page.tsx +2 -2
  22. package/src/app/tasks/page.tsx +5 -0
  23. package/src/components/costs/cost-dashboard.tsx +226 -320
  24. package/src/components/dashboard/activity-feed.tsx +6 -2
  25. package/src/components/notifications/batch-proposal-review.tsx +150 -0
  26. package/src/components/notifications/notification-item.tsx +6 -3
  27. package/src/components/notifications/pending-approval-host.tsx +57 -11
  28. package/src/components/playbook/adoption-heatmap.tsx +69 -0
  29. package/src/components/playbook/journey-card.tsx +110 -0
  30. package/src/components/playbook/playbook-action-button.tsx +22 -0
  31. package/src/components/playbook/playbook-browser.tsx +143 -0
  32. package/src/components/playbook/playbook-card.tsx +102 -0
  33. package/src/components/playbook/playbook-detail-view.tsx +223 -0
  34. package/src/components/playbook/playbook-homepage.tsx +142 -0
  35. package/src/components/playbook/playbook-toc.tsx +90 -0
  36. package/src/components/playbook/playbook-updated-badge.tsx +23 -0
  37. package/src/components/playbook/related-docs.tsx +30 -0
  38. package/src/components/profiles/__tests__/learned-context-panel.test.tsx +175 -0
  39. package/src/components/profiles/context-proposal-review.tsx +7 -3
  40. package/src/components/profiles/learned-context-panel.tsx +116 -8
  41. package/src/components/profiles/profile-detail-view.tsx +7 -19
  42. package/src/components/profiles/profile-form-view.tsx +0 -22
  43. package/src/components/settings/__tests__/auth-config-section.test.tsx +147 -0
  44. package/src/components/settings/api-key-form.tsx +5 -43
  45. package/src/components/settings/auth-config-section.tsx +10 -6
  46. package/src/components/settings/auth-status-badge.tsx +8 -0
  47. package/src/components/settings/budget-guardrails-section.tsx +403 -620
  48. package/src/components/settings/connection-test-control.tsx +63 -0
  49. package/src/components/settings/permissions-section.tsx +85 -75
  50. package/src/components/settings/permissions-sections.tsx +24 -0
  51. package/src/components/settings/presets-section.tsx +159 -0
  52. package/src/components/settings/pricing-registry-panel.tsx +164 -0
  53. package/src/components/shared/app-sidebar.tsx +2 -0
  54. package/src/components/shared/command-palette.tsx +30 -0
  55. package/src/components/shared/light-markdown.tsx +134 -0
  56. package/src/components/workflows/loop-status-view.tsx +8 -4
  57. package/src/components/workflows/workflow-status-view.tsx +16 -9
  58. package/src/lib/agents/__tests__/claude-agent.test.ts +7 -2
  59. package/src/lib/agents/__tests__/learned-context.test.ts +500 -0
  60. package/src/lib/agents/__tests__/pattern-extractor.test.ts +243 -0
  61. package/src/lib/agents/__tests__/sweep.test.ts +202 -0
  62. package/src/lib/agents/claude-agent.ts +104 -78
  63. package/src/lib/agents/learned-context.ts +32 -28
  64. package/src/lib/agents/learning-session.ts +234 -0
  65. package/src/lib/agents/pattern-extractor.ts +34 -64
  66. package/src/lib/agents/profiles/__tests__/sort.test.ts +42 -0
  67. package/src/lib/agents/profiles/builtins/code-reviewer/profile.yaml +0 -1
  68. package/src/lib/agents/profiles/builtins/data-analyst/profile.yaml +0 -1
  69. package/src/lib/agents/profiles/builtins/devops-engineer/profile.yaml +0 -1
  70. package/src/lib/agents/profiles/builtins/document-writer/profile.yaml +0 -1
  71. package/src/lib/agents/profiles/builtins/general/profile.yaml +0 -1
  72. package/src/lib/agents/profiles/builtins/health-fitness-coach/profile.yaml +0 -1
  73. package/src/lib/agents/profiles/builtins/learning-coach/profile.yaml +0 -1
  74. package/src/lib/agents/profiles/builtins/project-manager/profile.yaml +0 -1
  75. package/src/lib/agents/profiles/builtins/researcher/profile.yaml +0 -1
  76. package/src/lib/agents/profiles/builtins/shopping-assistant/profile.yaml +0 -1
  77. package/src/lib/agents/profiles/builtins/sweep/profile.yaml +0 -1
  78. package/src/lib/agents/profiles/builtins/technical-writer/profile.yaml +0 -1
  79. package/src/lib/agents/profiles/builtins/travel-planner/profile.yaml +0 -1
  80. package/src/lib/agents/profiles/builtins/wealth-manager/profile.yaml +0 -1
  81. package/src/lib/agents/profiles/registry.ts +0 -1
  82. package/src/lib/agents/profiles/sort.ts +7 -0
  83. package/src/lib/agents/profiles/types.ts +0 -1
  84. package/src/lib/agents/runtime/catalog.ts +1 -1
  85. package/src/lib/agents/runtime/claude.ts +66 -0
  86. package/src/lib/constants/settings.ts +1 -0
  87. package/src/lib/constants/task-status.ts +6 -0
  88. package/src/lib/data/seed-data/profiles.ts +0 -3
  89. package/src/lib/db/schema.ts +3 -0
  90. package/src/lib/docs/adoption.ts +105 -0
  91. package/src/lib/docs/journey-tracker.ts +21 -0
  92. package/src/lib/docs/reader.ts +102 -0
  93. package/src/lib/docs/types.ts +54 -0
  94. package/src/lib/docs/usage-stage.ts +60 -0
  95. package/src/lib/notifications/actionable.ts +18 -10
  96. package/src/lib/settings/__tests__/budget-guardrails.test.ts +86 -24
  97. package/src/lib/settings/budget-guardrails.ts +213 -85
  98. package/src/lib/settings/permission-presets.ts +150 -0
  99. package/src/lib/settings/runtime-setup.ts +71 -0
  100. package/src/lib/usage/__tests__/ledger.test.ts +29 -5
  101. package/src/lib/usage/__tests__/pricing-registry.test.ts +78 -0
  102. package/src/lib/usage/ledger.ts +4 -2
  103. package/src/lib/usage/pricing-registry.ts +570 -0
  104. package/src/lib/usage/pricing.ts +15 -41
  105. package/src/lib/utils/__tests__/learned-context-history.test.ts +171 -0
  106. package/src/lib/utils/learned-context-history.ts +150 -0
  107. package/src/lib/validators/__tests__/profile.test.ts +0 -15
  108. package/src/lib/validators/__tests__/settings.test.ts +23 -16
  109. package/src/lib/validators/profile.ts +0 -1
  110. package/src/lib/validators/settings.ts +3 -9
  111. package/src/lib/workflows/__tests__/engine.test.ts +2 -0
  112. package/src/lib/workflows/engine.ts +20 -1
@@ -1,15 +1,17 @@
1
1
  "use client";
2
2
 
3
3
  import { useState } from "react";
4
+ import { Eye, EyeOff, Loader2 } from "lucide-react";
5
+
4
6
  import { Button } from "@/components/ui/button";
5
7
  import { Input } from "@/components/ui/input";
6
8
  import { Label } from "@/components/ui/label";
7
- import { Loader2, Eye, EyeOff, CheckCircle2, XCircle } from "lucide-react";
9
+ import { ConnectionTestControl, type ConnectionTestResult } from "./connection-test-control";
8
10
 
9
11
  interface ApiKeyFormProps {
10
12
  hasKey: boolean;
11
13
  onSave: (key: string) => Promise<void>;
12
- onTest: () => Promise<{ connected: boolean; apiKeySource?: string; error?: string }>;
14
+ onTest: () => Promise<ConnectionTestResult & { apiKeySource?: string }>;
13
15
  keyPrefix?: string;
14
16
  placeholder?: string;
15
17
  maskedPrefix?: string;
@@ -31,16 +33,10 @@ export function ApiKeyForm({
31
33
  const [showInput, setShowInput] = useState(!hasKey);
32
34
  const [showKey, setShowKey] = useState(false);
33
35
  const [saving, setSaving] = useState(false);
34
- const [testing, setTesting] = useState(false);
35
- const [testResult, setTestResult] = useState<{
36
- connected: boolean;
37
- error?: string;
38
- } | null>(null);
39
36
 
40
37
  async function handleSave() {
41
38
  if (!key.startsWith(keyPrefix)) return;
42
39
  setSaving(true);
43
- setTestResult(null);
44
40
  try {
45
41
  await onSave(key);
46
42
  setKey("");
@@ -50,17 +46,6 @@ export function ApiKeyForm({
50
46
  }
51
47
  }
52
48
 
53
- async function handleTest() {
54
- setTesting(true);
55
- setTestResult(null);
56
- try {
57
- const result = await onTest();
58
- setTestResult(result);
59
- } finally {
60
- setTesting(false);
61
- }
62
- }
63
-
64
49
  return (
65
50
  <div className="space-y-4">
66
51
  <Label className="text-sm font-medium">API Key</Label>
@@ -108,30 +93,7 @@ export function ApiKeyForm({
108
93
  </div>
109
94
  )}
110
95
 
111
- <div className="flex items-center gap-3">
112
- <Button variant="outline" size="sm" onClick={handleTest} disabled={testing}>
113
- {testing && <Loader2 className="mr-1 h-3 w-3 animate-spin" />}
114
- {testButtonLabel}
115
- </Button>
116
-
117
- {testResult && (
118
- <span className="flex items-center gap-1.5 text-sm">
119
- {testResult.connected ? (
120
- <>
121
- <CheckCircle2 className="h-4 w-4 text-success" />
122
- <span className="text-success">Connected</span>
123
- </>
124
- ) : (
125
- <>
126
- <XCircle className="h-4 w-4 text-status-failed" />
127
- <span className="text-status-failed">
128
- {testResult.error || "Connection failed"}
129
- </span>
130
- </>
131
- )}
132
- </span>
133
- )}
134
- </div>
96
+ <ConnectionTestControl onTest={onTest} buttonLabel={testButtonLabel} />
135
97
 
136
98
  <p className="text-xs text-muted-foreground">
137
99
  Environment fallback: `{envVarName}`.
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useState, useEffect, useCallback } from "react";
4
+
4
5
  import {
5
6
  Card,
6
7
  CardContent,
@@ -12,6 +13,7 @@ import { Separator } from "@/components/ui/separator";
12
13
  import { AuthMethodSelector } from "./auth-method-selector";
13
14
  import { ApiKeyForm } from "./api-key-form";
14
15
  import { AuthStatusBadge } from "./auth-status-badge";
16
+ import { ConnectionTestControl } from "./connection-test-control";
15
17
  import type { AuthMethod, ApiKeySource } from "@/lib/constants/settings";
16
18
  import {
17
19
  DEFAULT_AGENT_RUNTIME,
@@ -32,6 +34,7 @@ export function AuthConfigSection() {
32
34
  apiKeySource: "unknown",
33
35
  });
34
36
  const [connected, setConnected] = useState(false);
37
+ const [testControlKey, setTestControlKey] = useState(0);
35
38
 
36
39
  const fetchSettings = useCallback(async () => {
37
40
  const res = await fetch("/api/settings");
@@ -55,6 +58,8 @@ export function AuthConfigSection() {
55
58
  if (res.ok) {
56
59
  const data = await res.json();
57
60
  setSettings(data);
61
+ setConnected(data.hasKey || data.apiKeySource === "oauth");
62
+ setTestControlKey((current) => current + 1);
58
63
  }
59
64
  }
60
65
 
@@ -102,6 +107,7 @@ export function AuthConfigSection() {
102
107
  <>
103
108
  <Separator />
104
109
  <ApiKeyForm
110
+ key={`api-key-form-${testControlKey}`}
105
111
  hasKey={settings.hasKey}
106
112
  onSave={handleSaveKey}
107
113
  onTest={handleTestConnection}
@@ -126,12 +132,10 @@ export function AuthConfigSection() {
126
132
  OAuth mode uses the Claude Agent SDK&apos;s built-in authentication flow.
127
133
  Requires an active Claude Max or Pro subscription.
128
134
  </p>
129
- <button
130
- onClick={handleTestConnection}
131
- className="text-sm text-primary hover:underline cursor-pointer"
132
- >
133
- Test OAuth connection
134
- </button>
135
+ <ConnectionTestControl
136
+ key={`oauth-test-${testControlKey}`}
137
+ onTest={handleTestConnection}
138
+ />
135
139
  </div>
136
140
  </>
137
141
  )}
@@ -32,6 +32,14 @@ export function AuthStatusBadge({ connected, apiKeySource }: AuthStatusBadgeProp
32
32
  );
33
33
  }
34
34
 
35
+ if (apiKeySource === "unknown") {
36
+ return (
37
+ <Badge variant="outline" className="border-success/50 text-success">
38
+ Connected
39
+ </Badge>
40
+ );
41
+ }
42
+
35
43
  return (
36
44
  <Badge variant="outline" className="border-success/50 text-success">
37
45
  Connected via {sourceLabels[apiKeySource]}