@workflow-code/cli 0.2.4-20261013004.codex-studio-integration → 0.2.4-20261013005.codex-studio-integration

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ async function main(argv = process.argv.slice(2)) {
24
24
  const prepared = prepareCliInvocation(argv);
25
25
  argv = prepared.argv;
26
26
  if (argv[0] === "web") {
27
- const webCli = await import("./web-JXC3WIJK.js");
27
+ const webCli = await import("./web-H4CP4OQC.js");
28
28
  return webCli.main(argv.slice(1));
29
29
  }
30
30
  if (argv[0] === "workspace") {
@@ -70,6 +70,7 @@ summary:focus-visible {
70
70
  }
71
71
  .project-heading {
72
72
  min-width: 0;
73
+ flex: 1;
73
74
  }
74
75
  #assistant-folder {
75
76
  display: block;
@@ -107,6 +108,9 @@ h1 {
107
108
  .project-name {
108
109
  color: var(--muted);
109
110
  font-size: 10px;
111
+ max-width: 160px;
112
+ overflow: hidden;
113
+ text-overflow: ellipsis;
110
114
  white-space: nowrap;
111
115
  }
112
116
  .toolbar-actions {
@@ -131,6 +135,15 @@ h1 {
131
135
  .icon-button:hover:not(:disabled) {
132
136
  background: var(--vscode-toolbar-hoverBackground);
133
137
  }
138
+ .usage-button {
139
+ width: auto;
140
+ gap: 6px;
141
+ padding: 0 8px;
142
+ color: var(--vscode-textLink-foreground);
143
+ white-space: nowrap;
144
+ font-size: 12px;
145
+ font-weight: 500;
146
+ }
134
147
  .toolbar-actions [aria-expanded=true] {
135
148
  background: var(--vscode-toolbar-activeBackground, var(--vscode-toolbar-hoverBackground));
136
149
  }
@@ -1304,6 +1317,52 @@ main {
1304
1317
  overflow: auto;
1305
1318
  padding: 16px;
1306
1319
  }
1320
+ .project-information-name {
1321
+ margin: 0 0 8px;
1322
+ font-size: 18px;
1323
+ line-height: 1.4;
1324
+ overflow-wrap: anywhere;
1325
+ }
1326
+ .project-information-description {
1327
+ margin: 0 0 16px;
1328
+ color: var(--muted);
1329
+ line-height: 1.6;
1330
+ white-space: pre-wrap;
1331
+ overflow-wrap: anywhere;
1332
+ }
1333
+ .project-information-section {
1334
+ padding: 10px 0;
1335
+ border-top: 1px solid var(--border);
1336
+ }
1337
+ .project-information-section summary {
1338
+ display: flex;
1339
+ align-items: center;
1340
+ gap: 6px;
1341
+ min-height: 28px;
1342
+ font-weight: 500;
1343
+ cursor: pointer;
1344
+ overflow-wrap: anywhere;
1345
+ }
1346
+ .project-information-section[open] summary > .codicon {
1347
+ transform: rotate(90deg);
1348
+ }
1349
+ .project-information-section dl {
1350
+ display: grid;
1351
+ grid-template-columns: minmax(80px, 130px) minmax(0, 1fr);
1352
+ gap: 12px 16px;
1353
+ margin: 12px 0 4px;
1354
+ line-height: 1.5;
1355
+ }
1356
+ .project-information-section dt {
1357
+ color: var(--muted);
1358
+ overflow-wrap: anywhere;
1359
+ }
1360
+ .project-information-section dd {
1361
+ margin: 0;
1362
+ white-space: pre-wrap;
1363
+ overflow-wrap: anywhere;
1364
+ user-select: text;
1365
+ }
1307
1366
  .action-dialog {
1308
1367
  width: min(380px, calc(100vw - 32px));
1309
1368
  }
@@ -1348,25 +1407,122 @@ main {
1348
1407
  .permissions-table td:not(:first-child) {
1349
1408
  text-align: center;
1350
1409
  }
1410
+ .usage-balance {
1411
+ display: flex;
1412
+ flex-wrap: wrap;
1413
+ align-items: baseline;
1414
+ gap: 8px 10px;
1415
+ padding: 4px 0 20px;
1416
+ }
1417
+ .usage-balance > span {
1418
+ flex-basis: 100%;
1419
+ color: var(--muted);
1420
+ font-size: 12px;
1421
+ }
1422
+ .usage-balance > strong {
1423
+ font-size: 28px;
1424
+ font-weight: 600;
1425
+ font-variant-numeric: tabular-nums;
1426
+ overflow-wrap: anywhere;
1427
+ }
1428
+ .usage-balance small {
1429
+ color: var(--muted);
1430
+ font-size: 11px;
1431
+ }
1432
+ .usage-status {
1433
+ display: flex;
1434
+ align-items: center;
1435
+ gap: 8px;
1436
+ min-height: 52px;
1437
+ margin: 0;
1438
+ color: var(--muted);
1439
+ overflow-wrap: anywhere;
1440
+ }
1441
+ .usage-status.error {
1442
+ color: var(--vscode-errorForeground);
1443
+ }
1444
+ .usage-status > .codicon-loading {
1445
+ animation: spin 1.2s linear infinite;
1446
+ }
1351
1447
  .usage-plan {
1352
- padding: 12px 0;
1448
+ display: grid;
1449
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1450
+ gap: 16px;
1451
+ padding: 18px 0;
1353
1452
  border-top: 1px solid var(--border);
1354
1453
  }
1355
1454
  .usage-plan h3 {
1356
- margin: 0 0 12px;
1357
- font-size: 13px;
1455
+ grid-column: 1 / -1;
1456
+ margin: 0;
1457
+ font-size: 14px;
1458
+ overflow-wrap: anywhere;
1358
1459
  }
1359
- .usage-plan > div {
1460
+ .usage-period {
1360
1461
  display: grid;
1361
- gap: 6px;
1362
- margin: 12px 0;
1462
+ align-content: start;
1463
+ gap: 10px;
1464
+ min-width: 0;
1363
1465
  font-size: 12px;
1364
1466
  }
1467
+ .usage-period-heading {
1468
+ display: flex;
1469
+ justify-content: space-between;
1470
+ align-items: baseline;
1471
+ flex-wrap: wrap;
1472
+ gap: 6px;
1473
+ }
1474
+ .usage-period-heading > span {
1475
+ color: var(--muted);
1476
+ }
1477
+ .usage-period-amount {
1478
+ display: flex;
1479
+ flex-wrap: wrap;
1480
+ align-items: baseline;
1481
+ gap: 4px;
1482
+ font-variant-numeric: tabular-nums;
1483
+ overflow-wrap: anywhere;
1484
+ }
1485
+ .usage-period-amount > strong {
1486
+ font-size: 18px;
1487
+ font-weight: 600;
1488
+ }
1489
+ .usage-period-amount > span,
1490
+ .usage-period-remaining {
1491
+ color: var(--muted);
1492
+ }
1365
1493
  .usage-plan progress {
1494
+ appearance: none;
1366
1495
  width: 100%;
1367
- height: 6px;
1496
+ height: 8px;
1497
+ border: 0;
1498
+ border-radius: 4px;
1499
+ overflow: hidden;
1500
+ background: var(--vscode-textCodeBlock-background);
1501
+ color: var(--vscode-progressBar-background);
1368
1502
  accent-color: var(--vscode-progressBar-background);
1369
1503
  }
1504
+ .usage-plan progress::-webkit-progress-bar {
1505
+ background: var(--vscode-textCodeBlock-background);
1506
+ }
1507
+ .usage-plan progress::-webkit-progress-value {
1508
+ background: var(--vscode-progressBar-background);
1509
+ }
1510
+ .usage-plan progress::-moz-progress-bar {
1511
+ background: var(--vscode-progressBar-background);
1512
+ }
1513
+ .usage-period[data-status=near-limit] {
1514
+ --vscode-progressBar-background: var(--vscode-editorWarning-foreground);
1515
+ }
1516
+ .usage-period[data-status=exhausted] {
1517
+ --vscode-progressBar-background: var(--vscode-errorForeground);
1518
+ }
1519
+ .usage-period[data-status=near-limit] .usage-period-heading > strong {
1520
+ color: var(--vscode-editorWarning-foreground);
1521
+ }
1522
+ .usage-period[data-status=exhausted] .usage-period-heading > strong,
1523
+ .usage-period[data-status=exhausted] .usage-period-remaining {
1524
+ color: var(--vscode-errorForeground);
1525
+ }
1370
1526
  .content-search {
1371
1527
  position: absolute;
1372
1528
  top: 4px;
@@ -1537,6 +1693,20 @@ textarea::placeholder {
1537
1693
  text-overflow: ellipsis;
1538
1694
  white-space: nowrap;
1539
1695
  }
1696
+ .param-action-summary {
1697
+ min-width: 0;
1698
+ overflow: hidden;
1699
+ text-overflow: ellipsis;
1700
+ white-space: nowrap;
1701
+ color: var(--vscode-editor-foreground);
1702
+ }
1703
+ .param-action:has(.param-action-summary:not([hidden])) .param-action-label {
1704
+ flex-shrink: 0;
1705
+ font-weight: 500;
1706
+ }
1707
+ .param-action-ai {
1708
+ color: var(--vscode-textLink-foreground);
1709
+ }
1540
1710
  .param-action .codicon {
1541
1711
  flex-shrink: 0;
1542
1712
  font-size: 13px;
@@ -1733,12 +1903,9 @@ textarea::placeholder {
1733
1903
  }
1734
1904
  @media (max-width: 680px) {
1735
1905
  #app.menu-open {
1736
- grid-template-areas: "menu" "main";
1906
+ grid-template-areas: "toolbar" "menu" "main";
1737
1907
  grid-template-columns: minmax(0, 1fr);
1738
- grid-template-rows: auto minmax(0, 1fr);
1739
- }
1740
- .menu-open .toolbar {
1741
- display: none;
1908
+ grid-template-rows: auto auto minmax(0, 1fr);
1742
1909
  }
1743
1910
  .toolbar {
1744
1911
  padding: 8px 12px;
@@ -1750,6 +1917,9 @@ textarea::placeholder {
1750
1917
  .project-name {
1751
1918
  display: none;
1752
1919
  }
1920
+ .project-icon {
1921
+ display: none;
1922
+ }
1753
1923
  .toolbar-actions {
1754
1924
  gap: 1px;
1755
1925
  }
@@ -1781,6 +1951,15 @@ textarea::placeholder {
1781
1951
  padding: 8px 18px 10px;
1782
1952
  }
1783
1953
  }
1954
+ @media (max-width: 520px) {
1955
+ .usage-plan {
1956
+ grid-template-columns: minmax(0, 1fr);
1957
+ gap: 18px;
1958
+ }
1959
+ .usage-period-amount > strong {
1960
+ font-size: 20px;
1961
+ }
1962
+ }
1784
1963
  @media (max-width: 420px) {
1785
1964
  .toolbar {
1786
1965
  padding: 8px;
@@ -1788,6 +1967,14 @@ textarea::placeholder {
1788
1967
  .project-title {
1789
1968
  gap: 2px;
1790
1969
  }
1970
+ .usage-button {
1971
+ gap: 4px;
1972
+ padding-inline: 5px;
1973
+ }
1974
+ .project-information-section dl {
1975
+ grid-template-columns: minmax(72px, 95px) minmax(0, 1fr);
1976
+ gap: 10px;
1977
+ }
1791
1978
  h1 {
1792
1979
  font-size: 13px;
1793
1980
  }
@@ -12607,6 +12607,44 @@
12607
12607
  "{0}{1} \xB7 {2} items": "\u5DF2{0}{1} \xB7 {2} \u9879",
12608
12608
  "{1} in {0}": "{0} \u4E2D {1}",
12609
12609
  "Account balance ${0}": "\u8D26\u6237\u4F59\u989D ${0}",
12610
+ "Account balance": "\u8D26\u6237\u4F59\u989D",
12611
+ "AI usage": "AI \u7528\u91CF",
12612
+ All: "\u5168\u90E8",
12613
+ "Basic information": "\u57FA\u672C\u4FE1\u606F",
12614
+ Declarations: "\u58F0\u660E",
12615
+ "Default name": "\u9ED8\u8BA4\u540D\u79F0",
12616
+ "Entrypoints granted": "\u5165\u53E3\u8C03\u7528\u6388\u6743",
12617
+ "Knowledge read granted": "\u77E5\u8BC6\u5E93\u8BFB\u53D6\u6388\u6743",
12618
+ "Knowledge write granted": "\u77E5\u8BC6\u5E93\u5199\u5165\u6388\u6743",
12619
+ "KV read granted": "KV \u8BFB\u53D6\u6388\u6743",
12620
+ "KV write granted": "KV \u5199\u5165\u6388\u6743",
12621
+ "Limit reached": "\u989D\u5EA6\u5DF2\u7528\u5C3D",
12622
+ "Loading usage...": "\u6B63\u5728\u52A0\u8F7D\u7528\u91CF...",
12623
+ Local: "\u672C\u5730",
12624
+ "Local and server": "\u672C\u5730\u4E0E\u670D\u52A1\u5668",
12625
+ "Local path": "\u672C\u5730\u8DEF\u5F84",
12626
+ "Localized names": "\u591A\u8BED\u8A00\u540D\u79F0",
12627
+ "Multiple languages": "\u591A\u8BED\u8A00",
12628
+ "Multiple platforms": "\u591A\u5E73\u53F0",
12629
+ "Not allowed": "\u4E0D\u5141\u8BB8",
12630
+ "Not available": "\u6682\u65E0\u6570\u636E",
12631
+ "Not declared": "\u672A\u58F0\u660E",
12632
+ "Platform independent": "\u5E73\u53F0\u65E0\u5173",
12633
+ "Platform support": "\u5E73\u53F0\u652F\u6301",
12634
+ Prefixes: "\u524D\u7F00",
12635
+ "Project declarations": "\u9879\u76EE\u58F0\u660E",
12636
+ "Project information": "\u9879\u76EE\u4FE1\u606F",
12637
+ "Project type": "\u9879\u76EE\u7C7B\u578B",
12638
+ "Project UUID": "\u9879\u76EE UUID",
12639
+ "Related project: {0}": "\u5173\u8054\u9879\u76EE\uFF1A{0}",
12640
+ "Storage location": "\u5B58\u50A8\u4F4D\u7F6E",
12641
+ "Usage unavailable": "\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\u7528\u91CF",
12642
+ Used: "\u5DF2\u4F7F\u7528",
12643
+ Version: "\u7248\u672C",
12644
+ "Working directory": "\u5DE5\u4F5C\u76EE\u5F55",
12645
+ "{0} (default)": "{0}\uFF08\u9ED8\u8BA4\uFF09",
12646
+ "{0} remaining": "\u5269\u4F59 {0}",
12647
+ "{0} usage": "{0}\u7528\u91CF",
12610
12648
  "Add attachment": "\u6DFB\u52A0\u9644\u4EF6",
12611
12649
  "Agent run": "Agent \u8FD0\u884C",
12612
12650
  "All chats": "\u5168\u90E8\u804A\u5929",
@@ -16070,6 +16108,17 @@ ${state2.user?.avatarUrl ?? ""}`;
16070
16108
  }
16071
16109
 
16072
16110
  // src/web/workflow-types.ts
16111
+ var projectTypeLabels = {
16112
+ get conversation() {
16113
+ return t2("Conversation");
16114
+ },
16115
+ get workflow() {
16116
+ return t2("Workflow");
16117
+ },
16118
+ get kanban() {
16119
+ return t2("Kanban");
16120
+ }
16121
+ };
16073
16122
  function workflowParamValue(field, value = field.defaultValue ?? "") {
16074
16123
  if (field.type === "file" || field.control === "audio" || !(field.multiple || field.control === "checkboxes") || Array.isArray(value)) {
16075
16124
  return value;
@@ -16171,11 +16220,20 @@ ${state2.user?.avatarUrl ?? ""}`;
16171
16220
  const label = document.createElement("span");
16172
16221
  label.className = "param-action-label";
16173
16222
  const view = { action: action2, button, label };
16223
+ if (action2.kind === "quick" && action2.id === "ai") {
16224
+ button.classList.add("param-action-ai");
16225
+ button.append(icon("sparkle"));
16226
+ }
16174
16227
  if (action2.kind === "auxiliary") {
16175
16228
  button.append(icon("settings"));
16176
16229
  view.count = document.createElement("small");
16177
16230
  }
16178
16231
  button.append(label);
16232
+ if (action2.kind === "quick") {
16233
+ view.summary = document.createElement("span");
16234
+ view.summary.className = "param-action-summary";
16235
+ button.append(view.summary);
16236
+ }
16179
16237
  if (view.count) {
16180
16238
  button.append(view.count);
16181
16239
  }
@@ -16232,14 +16290,17 @@ ${state2.user?.avatarUrl ?? ""}`;
16232
16290
  view.button.hidden = fields2.length === 0;
16233
16291
  view.button.disabled = disabled || (action2.kind === "auxiliary" ? loading : fields2.every((field) => states[field.name]?.disabled === true || this.visibleOptions(field).length === 0));
16234
16292
  const summaries = action2.summary?.map((name) => fields2.find((field) => field.name === name)).filter((field) => !!field && !!values2[field.name]?.length).map((field) => parameterSelectionLabel(field, values2[field.name], states[field.name])) ?? [];
16235
- view.label.textContent = action2.kind === "quick" && summaries.length ? `${action2.label}: ${summaries.join(" \xB7 ")}` : action2.label;
16293
+ view.label.textContent = action2.label;
16294
+ if (view.summary) {
16295
+ view.summary.textContent = summaries.join(" \xB7 ");
16296
+ view.summary.hidden = !summaries.length;
16297
+ }
16236
16298
  if (view.count) {
16237
16299
  view.count.textContent = String(fields2.length);
16238
16300
  }
16239
16301
  view.button.setAttribute("aria-busy", String(loading));
16240
16302
  }
16241
- view.button.title = view.label.textContent || "";
16242
- view.button.ariaLabel = view.label.textContent || "";
16303
+ view.button.title = view.button.ariaLabel = [view.label.textContent, view.summary?.textContent].filter(Boolean).join(": ");
16243
16304
  }
16244
16305
  if (this.active) {
16245
16306
  if (disabled || this.active.button.hidden) {
@@ -16676,6 +16737,89 @@ ${state2.user?.avatarUrl ?? ""}`;
16676
16737
  }
16677
16738
  };
16678
16739
 
16740
+ // src/web/ui/project-information.ts
16741
+ function access(rule) {
16742
+ if (rule?.mode === "all") {
16743
+ return t2("All");
16744
+ }
16745
+ if (rule?.mode === "none") {
16746
+ return t2("Not allowed");
16747
+ }
16748
+ if (rule?.mode === "prefixes") {
16749
+ return `${t2("Prefixes")}: ${rule.prefixes.join(", ")}`;
16750
+ }
16751
+ return t2("Not declared");
16752
+ }
16753
+ function projectInformation(project2) {
16754
+ const info = project2.projectInfo;
16755
+ const storage = { local: t2("Local"), server: t2("Server"), both: t2("Local and server") };
16756
+ const declarations = { multilingual: t2("Multiple languages"), multiplatform: t2("Multiple platforms") };
16757
+ const platforms = { macos: "macOS", windows: "Windows", web: "Web" };
16758
+ const sections = [{
16759
+ title: t2("Basic information"),
16760
+ expanded: true,
16761
+ rows: [
16762
+ { label: t2("Default name"), value: project2.manifest?.name || project2.name },
16763
+ { label: t2("Project type"), value: projectTypeLabels[project2.projectType] },
16764
+ { label: t2("Version"), value: project2.manifest?.version || t2("Not declared") },
16765
+ { label: t2("Project UUID"), value: project2.id },
16766
+ { label: project2.assistant ? t2("Working directory") : t2("Local path"), value: project2.assistant?.workdir || project2.folderPath }
16767
+ ]
16768
+ }, {
16769
+ title: t2("Project declarations"),
16770
+ expanded: true,
16771
+ rows: [
16772
+ { label: t2("Storage location"), value: info?.dataStorage ? storage[info.dataStorage.mode] : t2("Not declared") },
16773
+ { label: t2("Platform support"), value: info?.platformSupport.mode === "specific" ? info.platformSupport.platforms.map((id) => platforms[id] || id).join(", ") : t2("Platform independent") },
16774
+ { label: t2("Declarations"), value: info?.declarations.map((id) => declarations[id] || id).join(", ") || t2("Not declared") }
16775
+ ]
16776
+ }];
16777
+ if (info && Object.keys(info.localizedNames).length) {
16778
+ sections.push({ title: t2("Localized names"), rows: Object.entries(info.localizedNames).map(([label, value]) => ({ label, value })) });
16779
+ }
16780
+ for (const relation of info?.relatedProjects ?? []) {
16781
+ const grant = relation.grantToRelatedProject;
16782
+ sections.push({ title: t2("Related project: {0}", relation.alias), rows: [
16783
+ { label: t2("Project UUID"), value: relation.projectId },
16784
+ { label: t2("KV read granted"), value: access(grant.read) },
16785
+ { label: t2("KV write granted"), value: access(grant.write) },
16786
+ { label: t2("Knowledge read granted"), value: access(grant.knowledge?.read) },
16787
+ { label: t2("Knowledge write granted"), value: access(grant.knowledge?.write) },
16788
+ { label: t2("Entrypoints granted"), value: access(grant.entrypoints) }
16789
+ ] });
16790
+ }
16791
+ if (project2.entrypoints.length) {
16792
+ sections.push({ title: t2("Entrypoints"), rows: project2.entrypoints.map((entry) => ({
16793
+ label: entry.title || entry.id,
16794
+ value: entry.id === project2.defaultEntrypoint ? t2("{0} (default)", entry.id) : entry.id
16795
+ })) });
16796
+ }
16797
+ return sections;
16798
+ }
16799
+
16800
+ // src/web/ui/ai-usage.ts
16801
+ function usageAmount(value) {
16802
+ return value != null && Number.isFinite(Number(value)) ? `$${Math.max(0, Number(value)).toFixed(2)}` : t2("Not available");
16803
+ }
16804
+ function usagePeriods(subscription) {
16805
+ const labels = { daily: t2("Daily"), weekly: t2("Weekly"), monthly: t2("Monthly") };
16806
+ return ["daily", "weekly", "monthly"].map((period) => {
16807
+ const rawUsed = subscription[`${period}UsageUsd`], rawLimit = subscription[`${period}LimitUsd`];
16808
+ const used = Number.isFinite(Number(rawUsed)) && rawUsed != null ? Math.max(0, Number(rawUsed)) : void 0;
16809
+ const limit = rawLimit === null ? null : Number.isFinite(Number(rawLimit)) && rawLimit !== void 0 ? Math.max(0, Number(rawLimit)) : void 0;
16810
+ const ratio = used !== void 0 && limit !== null && limit !== void 0 ? limit > 0 ? used / limit : 1 : void 0;
16811
+ return {
16812
+ period,
16813
+ label: labels[period],
16814
+ used,
16815
+ limit,
16816
+ ratio,
16817
+ status: ratio === void 0 ? "" : ratio >= 1 ? "exhausted" : ratio >= 0.8 ? "near-limit" : "",
16818
+ remaining: used !== void 0 && limit !== null && limit !== void 0 ? Math.max(0, limit - used) : void 0
16819
+ };
16820
+ });
16821
+ }
16822
+
16679
16823
  // src/web/ui/conversation-tools.ts
16680
16824
  var ConversationTools = class {
16681
16825
  dialog = document.createElement("dialog");
@@ -16685,6 +16829,8 @@ ${state2.user?.avatarUrl ?? ""}`;
16685
16829
  refresh;
16686
16830
  constructor() {
16687
16831
  this.dialog.className = "conversation-dialog";
16832
+ this.title.id = "conversation-dialog-title";
16833
+ this.dialog.setAttribute("aria-labelledby", this.title.id);
16688
16834
  const header = document.createElement("header");
16689
16835
  header.append(this.title, iconButton("close", t2("Close"), () => this.close()));
16690
16836
  this.body.className = "dialog-body";
@@ -16698,6 +16844,7 @@ ${state2.user?.avatarUrl ?? ""}`;
16698
16844
  }
16699
16845
  }
16700
16846
  });
16847
+ this.dialog.addEventListener("cancel", () => this.close());
16701
16848
  }
16702
16849
  get open() {
16703
16850
  return this.dialog.open;
@@ -16712,6 +16859,7 @@ ${state2.user?.avatarUrl ?? ""}`;
16712
16859
  this.close();
16713
16860
  this.title.textContent = title;
16714
16861
  this.body.replaceChildren();
16862
+ this.body.setAttribute("aria-busy", "false");
16715
16863
  this.dialog.showModal();
16716
16864
  }
16717
16865
  plan(content) {
@@ -16729,6 +16877,35 @@ ${state2.user?.avatarUrl ?? ""}`;
16729
16877
  image.className = "image-preview";
16730
16878
  this.body.append(image);
16731
16879
  }
16880
+ projectInfo(project2) {
16881
+ this.show(t2("Project information"));
16882
+ const heading = document.createElement("h3");
16883
+ heading.className = "project-information-name";
16884
+ heading.textContent = project2.name;
16885
+ this.body.append(heading);
16886
+ if (project2.manifest?.description) {
16887
+ const description = document.createElement("p");
16888
+ description.className = "project-information-description";
16889
+ description.textContent = project2.manifest.description;
16890
+ this.body.append(description);
16891
+ }
16892
+ for (const section of projectInformation(project2)) {
16893
+ const details = document.createElement("details");
16894
+ details.className = "project-information-section";
16895
+ details.open = !!section.expanded;
16896
+ const summary = document.createElement("summary");
16897
+ summary.innerHTML = `${iconHtml("chevron-right")}<span>${escapeHtml(section.title)}</span>`;
16898
+ const list = document.createElement("dl");
16899
+ for (const row of section.rows) {
16900
+ const label = document.createElement("dt"), value = document.createElement("dd");
16901
+ label.textContent = row.label;
16902
+ value.textContent = row.value;
16903
+ list.append(label, value);
16904
+ }
16905
+ details.append(summary, list);
16906
+ this.body.append(details);
16907
+ }
16908
+ }
16732
16909
  permissions(parameters, policies, changed) {
16733
16910
  this.show(t2("Tool permissions"));
16734
16911
  const tools = parameters.tools ?? [];
@@ -16772,14 +16949,18 @@ ${state2.user?.avatarUrl ?? ""}`;
16772
16949
  }
16773
16950
  }
16774
16951
  usage(load) {
16775
- this.show(t2("System AI"));
16952
+ this.show(t2("AI usage"));
16776
16953
  this.usageOpen = true;
16777
- const refresh = this.refresh = iconButton("refresh", t2("Refresh usage"), () => {
16778
- this.body.textContent = t2("Loading...");
16779
- load();
16780
- });
16954
+ const refresh = this.refresh = iconButton("refresh", t2("Refresh usage"), () => this.loadUsage(load));
16781
16955
  this.dialog.querySelector("header").insertBefore(refresh, this.dialog.querySelector("header > button:last-child"));
16782
- this.body.textContent = t2("Loading...");
16956
+ this.loadUsage(load);
16957
+ }
16958
+ loadUsage(load) {
16959
+ this.body.innerHTML = `<div class="usage-status" role="status">${iconHtml("loading")}<span>${t2("Loading usage...")}</span></div>`;
16960
+ this.body.setAttribute("aria-busy", "true");
16961
+ if (this.refresh) {
16962
+ this.refresh.disabled = true;
16963
+ }
16783
16964
  load();
16784
16965
  }
16785
16966
  usageResult(data, error) {
@@ -16787,20 +16968,26 @@ ${state2.user?.avatarUrl ?? ""}`;
16787
16968
  return;
16788
16969
  }
16789
16970
  this.body.replaceChildren();
16790
- if (error) {
16791
- this.body.textContent = error;
16792
- return;
16793
- }
16794
- if (!data) {
16971
+ this.body.setAttribute("aria-busy", "false");
16972
+ if (this.refresh) {
16973
+ this.refresh.disabled = false;
16974
+ }
16975
+ if (error || !data) {
16976
+ const status = document.createElement("p");
16977
+ status.className = error ? "error usage-status" : "usage-status";
16978
+ status.setAttribute("role", error ? "alert" : "status");
16979
+ status.textContent = error || t2("Usage unavailable");
16980
+ this.body.append(status);
16795
16981
  return;
16796
16982
  }
16797
- const balance = document.createElement("p");
16798
- balance.textContent = t2("Account balance ${0}", Number(data.balance ?? 0).toFixed(2));
16983
+ const balance = document.createElement("div");
16984
+ balance.className = "usage-balance";
16985
+ balance.innerHTML = `<span>${t2("Account balance")}</span><strong>${escapeHtml(usageAmount(data.balance))}</strong><small>USD</small>`;
16799
16986
  this.body.append(balance);
16800
- const labels = { daily: t2("Daily"), weekly: t2("Weekly"), monthly: t2("Monthly") };
16801
16987
  const plans = data.groups.filter((group) => group.subscriptionType === "subscription" && group.subscription?.status === "active");
16802
16988
  if (!plans.length) {
16803
16989
  const empty = document.createElement("p");
16990
+ empty.className = "usage-status";
16804
16991
  empty.textContent = t2("No active subscriptions");
16805
16992
  this.body.append(empty);
16806
16993
  }
@@ -16810,19 +16997,24 @@ ${state2.user?.avatarUrl ?? ""}`;
16810
16997
  const title = document.createElement("h3");
16811
16998
  title.textContent = plan.name;
16812
16999
  section.append(title);
16813
- for (const period of ["daily", "weekly", "monthly"]) {
16814
- const limit = plan.subscription[`${period}LimitUsd`];
16815
- const used = Number(plan.subscription[`${period}UsageUsd`] ?? 0);
17000
+ for (const period of usagePeriods(plan.subscription)) {
16816
17001
  const row = document.createElement("div");
16817
- const label = document.createElement("span");
16818
- label.textContent = `${labels[period]} $${used.toFixed(2)} / ${limit === null ? t2("Unlimited") : `$${Number(limit).toFixed(2)}`}`;
16819
- row.append(label);
16820
- if (limit !== null && limit > 0) {
17002
+ row.className = "usage-period";
17003
+ row.dataset.status = period.status;
17004
+ const used = period.used === void 0 ? t2("Not available") : usageAmount(period.used);
17005
+ const limit = period.limit === null ? t2("Unlimited") : period.limit === void 0 ? t2("Not available") : usageAmount(period.limit);
17006
+ row.innerHTML = `<div class="usage-period-heading"><span>${period.label}</span><strong>${period.ratio === void 0 ? escapeHtml(limit) : `${Math.round(period.ratio * 100)}%`}</strong></div><div class="usage-period-amount"><strong>${escapeHtml(used)}</strong><span>/ ${escapeHtml(limit)}</span></div>`;
17007
+ if (period.ratio !== void 0) {
16821
17008
  const progress = document.createElement("progress");
16822
- progress.max = limit;
16823
- progress.value = used;
17009
+ progress.max = 1;
17010
+ progress.value = Math.min(1, period.ratio);
17011
+ progress.ariaLabel = t2("{0} usage", period.label);
16824
17012
  row.append(progress);
16825
17013
  }
17014
+ const remaining = document.createElement("span");
17015
+ remaining.className = "usage-period-remaining";
17016
+ remaining.textContent = period.status === "exhausted" ? t2("Limit reached") : period.remaining === void 0 ? t2("Used") : t2("{0} remaining", usageAmount(period.remaining));
17017
+ row.append(remaining);
16826
17018
  section.append(row);
16827
17019
  }
16828
17020
  this.body.append(section);
@@ -17243,7 +17435,7 @@ ${state2.user?.avatarUrl ?? ""}`;
17243
17435
  var host = acquireWorkflowHost();
17244
17436
  app.classList.add("kanban-app");
17245
17437
  app.innerHTML = `
17246
- <header class="toolbar"><div class="project-title"><button id="menu-toggle" class="icon-button" aria-label="${t2("Show Kanban configurations")}" title="${t2("Show Kanban configurations")}">${iconHtml("layout-sidebar-left")}</button><span class="project-icon">${iconHtml("layout")}</span><h1 id="kanban-title">Kanban</h1></div><div class="toolbar-actions"><div id="preview-modes" class="kanban-modes" role="group" aria-label="${t2("Preview size")}"></div><button id="dimensions" class="icon-button" title="${t2("Resize preview")}" aria-label="${t2("Resize preview")}" hidden>${iconHtml("settings")}</button><button id="refresh" class="icon-button" title="${t2("Refresh Kanban")}" aria-label="${t2("Refresh Kanban")}">${iconHtml("refresh")}</button><button id="usage" class="icon-button" title="${t2("System AI usage")}" aria-label="${t2("System AI usage")}" hidden>${iconHtml("dashboard")}</button><button id="methods" class="icon-button" title="${t2("Page methods")}" aria-label="${t2("Page methods")}">${iconHtml("tools")}</button></div></header>
17438
+ <header class="toolbar"><div class="project-title"><button id="menu-toggle" class="icon-button" aria-label="${t2("Show Kanban configurations")}" title="${t2("Show Kanban configurations")}">${iconHtml("layout-sidebar-left")}</button><button id="project-info" class="icon-button" title="${t2("Project information")}" aria-label="${t2("Project information")}" aria-haspopup="dialog">${iconHtml("info")}</button><span class="project-icon">${iconHtml("layout")}</span><h1 id="kanban-title">Kanban</h1></div><div class="toolbar-actions"><div id="preview-modes" class="kanban-modes" role="group" aria-label="${t2("Preview size")}"></div><button id="dimensions" class="icon-button" title="${t2("Resize preview")}" aria-label="${t2("Resize preview")}" hidden>${iconHtml("settings")}</button><button id="refresh" class="icon-button" title="${t2("Refresh Kanban")}" aria-label="${t2("Refresh Kanban")}">${iconHtml("refresh")}</button><button id="usage" class="icon-button usage-button" title="${t2("System AI usage")}" aria-label="${t2("System AI usage")}" aria-haspopup="dialog" hidden>${iconHtml("dashboard")}<span>${t2("AI usage")}</span></button><button id="methods" class="icon-button" title="${t2("Page methods")}" aria-label="${t2("Page methods")}">${iconHtml("tools")}</button></div></header>
17247
17439
  <aside id="project-menu" class="project-menu" aria-label="${t2("Kanban configurations")}"><div class="menu-heading"><span>${t2("Kanban configurations")}</span><button id="hide-menu" class="icon-button" title="${t2("Hide Kanban configurations")}" aria-label="${t2("Hide Kanban configurations")}">${iconHtml("chevron-left")}</button></div><div id="configuration-editor"><div class="kanban-configuration-controls"><select id="configuration" aria-label="${t2("Current configuration")}"></select><button id="create" class="icon-button" title="${t2("New configuration")}" aria-label="${t2("New configuration")}">${iconHtml("add")}</button><button id="configuration-actions" class="icon-button" title="${t2("Configuration actions")}" aria-label="${t2("Configuration actions")}">${iconHtml("ellipsis")}</button></div><div id="save-error" class="error" hidden role="alert"><span></span><button id="retry-save" class="icon-button" title="${t2("Retry save")}" aria-label="${t2("Retry save")}">${iconHtml("refresh")}</button></div><div id="kanban-fields"></div><div id="parameter-actions"></div></div></aside>
17248
17440
  <main><div id="error" class="error" hidden role="alert"></div><div id="related-warning" class="kanban-warning" hidden role="status"></div><div id="preview-stage"><div id="preview-viewport"><iframe id="kanban-preview" title="Kanban" sandbox="allow-scripts"></iframe><button id="resize-preview" class="kanban-resize" title="${t2("Resize preview")}" aria-label="${t2("Resize preview")}" hidden>${iconHtml("arrow-both")}</button></div><div id="preview-status" class="kanban-status" role="status"><span class="codicon codicon-loading"></span><span>${t2("Loading Kanban")}</span><button id="retry-preview" class="icon-button" title="${t2("Retry")}" aria-label="${t2("Retry")}" hidden>${iconHtml("refresh")}</button></div><div id="preview-offline" hidden></div></div></main>
17249
17441
  <dialog id="configuration-dialog" class="conversation-dialog"><header><h2>${t2("Configuration actions")}</h2><button id="close-configurations" class="icon-button" title="${t2("Close")}" aria-label="${t2("Close")}">${iconHtml("close")}</button></header><div class="dialog-body configuration-command-list"></div></dialog>
@@ -17657,6 +17849,11 @@ ${state2.user?.avatarUrl ?? ""}`;
17657
17849
  }
17658
17850
  };
17659
17851
  element("usage").onclick = () => dialogs.usage(() => host.postMessage({ type: "usage" }));
17852
+ element("project-info").onclick = () => {
17853
+ if (project) {
17854
+ dialogs.projectInfo(project);
17855
+ }
17856
+ };
17660
17857
  window.addEventListener("message", (event) => {
17661
17858
  const message = event.data;
17662
17859
  if (event.source === frame.contentWindow) {