agent-canvas 0.2.1 → 0.6.0

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 (99) hide show
  1. package/README.md +42 -17
  2. package/bin/agent-canvas.js +7 -7
  3. package/bin/agent-canvas.ts +48 -37
  4. package/bin/lib/commands/daemon.ts +46 -43
  5. package/bin/lib/commands/exec.ts +100 -100
  6. package/bin/lib/commands/fetch.ts +15 -15
  7. package/bin/lib/commands/install.ts +36 -36
  8. package/bin/lib/commands/instructions.ts +51 -51
  9. package/bin/lib/commands/push.ts +115 -97
  10. package/bin/lib/commands/review.ts +190 -0
  11. package/bin/lib/commands/watch.ts +24 -24
  12. package/bin/lib/config.ts +12 -12
  13. package/bin/lib/daemon-lifecycle.ts +47 -51
  14. package/bin/lib/helpers.ts +82 -76
  15. package/bin/lib/instructions/app-review.md +88 -0
  16. package/bin/lib/instructions/component-checklist.md +7 -5
  17. package/bin/lib/instructions/component-custom.md +20 -14
  18. package/bin/lib/instructions/component-diff.md +4 -3
  19. package/bin/lib/instructions/component-item.md +18 -8
  20. package/bin/lib/instructions/component-markdown.md +4 -2
  21. package/bin/lib/instructions/component-mermaid.md +12 -6
  22. package/bin/lib/instructions/component-multichoice.md +6 -2
  23. package/bin/lib/instructions/component-note.md +1 -1
  24. package/bin/lib/instructions/component-priority.md +1 -1
  25. package/bin/lib/instructions/component-rangeinput.md +9 -2
  26. package/bin/lib/instructions/component-secretinput.md +12 -11
  27. package/bin/lib/instructions/component-svg.md +62 -16
  28. package/bin/lib/instructions/component-table.md +6 -6
  29. package/bin/lib/instructions/component-usefeedback.md +8 -8
  30. package/bin/lib/instructions/component-userinput.md +6 -2
  31. package/bin/lib/instructions/flow-feature.md +22 -5
  32. package/bin/lib/instructions/flow-plan.md +5 -5
  33. package/bin/lib/instructions/flow-runbook.md +28 -25
  34. package/bin/lib/instructions/overview.md +27 -18
  35. package/bin/lib/instructions/theming.md +5 -0
  36. package/daemon/build.ts +171 -152
  37. package/daemon/client/App.tsx +1205 -1077
  38. package/daemon/client/CompareView.tsx +478 -458
  39. package/daemon/client/FileBrowser.tsx +241 -203
  40. package/daemon/client/FileViewer.tsx +220 -211
  41. package/daemon/client/OverviewView.tsx +283 -267
  42. package/daemon/client/ReviewerIdentityDialog.tsx +72 -71
  43. package/daemon/client/RevisionSelect.tsx +111 -95
  44. package/daemon/client/SessionSwitcher.tsx +81 -81
  45. package/daemon/client/ShareDialog.tsx +211 -212
  46. package/daemon/client/apiSchemas.ts +78 -0
  47. package/daemon/client/canvas-runtime.ts +1 -1
  48. package/daemon/client/clientApi.ts +194 -206
  49. package/daemon/client/components/SecretInput.tsx +138 -138
  50. package/daemon/client/components/index.ts +2 -2
  51. package/daemon/client/domDiff.ts +341 -333
  52. package/daemon/client/errorMessage.ts +3 -0
  53. package/daemon/client/exportMarkdown.ts +222 -201
  54. package/daemon/client/lcs.ts +19 -14
  55. package/daemon/client/shareCrypto.ts +57 -57
  56. package/daemon/client/unifiedDiff.ts +660 -649
  57. package/daemon/dist/annotations-runtime.js +1 -1
  58. package/daemon/dist/client.css +2 -2
  59. package/daemon/dist/client.js +77 -80
  60. package/daemon/dist/components.js +59 -59
  61. package/daemon/dist/preact-compat.js +1 -1
  62. package/daemon/dist/review.js +361 -0
  63. package/daemon/dist/runtime.js +1 -1
  64. package/daemon/langMap.ts +24 -6
  65. package/daemon/review-widget/anchor.ts +187 -0
  66. package/daemon/review-widget/client.ts +95 -0
  67. package/daemon/review-widget/index.tsx +36 -0
  68. package/daemon/review-widget/markup.ts +71 -0
  69. package/daemon/review-widget/screenshot.ts +91 -0
  70. package/daemon/review-widget/source.ts +103 -0
  71. package/daemon/review-widget/styles.css +359 -0
  72. package/daemon/review-widget/text-modules.d.ts +4 -0
  73. package/daemon/review-widget/tsconfig.json +16 -0
  74. package/daemon/review-widget/widget.tsx +436 -0
  75. package/daemon/src/components.ts +3 -3
  76. package/daemon/src/handlers/api.ts +330 -328
  77. package/daemon/src/handlers/files.ts +112 -106
  78. package/daemon/src/handlers/static.ts +47 -46
  79. package/daemon/src/handlers/uploads.ts +61 -56
  80. package/daemon/src/paths.ts +13 -10
  81. package/daemon/src/remote-feedback.ts +192 -192
  82. package/daemon/src/review/markdown.ts +52 -0
  83. package/daemon/src/review/model.ts +132 -0
  84. package/daemon/src/review/proxy.ts +177 -0
  85. package/daemon/src/review/server.ts +199 -0
  86. package/daemon/src/review/store.ts +151 -0
  87. package/daemon/src/server.ts +127 -86
  88. package/daemon/src/share.ts +163 -169
  89. package/daemon/src/stubFetch.ts +7 -0
  90. package/daemon/tsconfig.json +19 -19
  91. package/package.json +47 -47
  92. package/skills/canvas/SKILL.md +5 -1
  93. package/bin/lib/commands/exec.test.ts +0 -27
  94. package/bin/lib/helpers.test.ts +0 -79
  95. package/daemon/src/files-api.test.ts +0 -78
  96. package/daemon/src/remote-feedback.test.ts +0 -165
  97. package/daemon/src/secrets-api.test.ts +0 -123
  98. package/daemon/src/share-e2e.test.ts +0 -277
  99. package/daemon/src/share.test.ts +0 -289
@@ -1,156 +1,156 @@
1
- import React, { useEffect, useState } from "react";
2
- import { useFeedback } from "#canvas/runtime";
3
- import { MODE, clearLocalSecret, getLocalSecretStatus, storeLocalSecret } from "../clientApi";
1
+ import { useFeedback } from '#canvas/runtime'
2
+ import { useEffect, useState } from 'react'
3
+ import { clearLocalSecret, getLocalSecretStatus, MODE, storeLocalSecret } from '../clientApi'
4
4
 
5
- const FIELD_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
6
- const ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
5
+ const FIELD_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/
6
+ const ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/
7
7
 
8
8
  interface SecretInputProps {
9
- id: string;
10
- label: string;
11
- env: string;
12
- placeholder?: string;
13
- required?: boolean;
9
+ id: string
10
+ label: string
11
+ env: string
12
+ placeholder?: string
13
+ required?: boolean
14
14
  }
15
15
 
16
16
  /** Local-only secret handoff that never enters annotation or feedback state. */
17
17
  export function SecretInput({ id, label, env, placeholder, required }: SecretInputProps) {
18
- const [value, setValue] = useState("");
19
- const [ready, setReady] = useState(false);
20
- const [busy, setBusy] = useState(!MODE.isShared);
21
- const [error, setError] = useState<string | null>(null);
22
- const validFieldId = FIELD_ID_RE.test(id);
23
- const validEnvName = ENV_NAME_RE.test(env);
24
- const locallyAvailable = !MODE.isShared;
18
+ const [value, setValue] = useState('')
19
+ const [ready, setReady] = useState(false)
20
+ const [busy, setBusy] = useState(!MODE.isShared)
21
+ const [error, setError] = useState<string | null>(null)
22
+ const validFieldId = FIELD_ID_RE.test(id)
23
+ const validEnvName = ENV_NAME_RE.test(env)
24
+ const locallyAvailable = !MODE.isShared
25
25
 
26
- useEffect(() => {
27
- if (!locallyAvailable || !validFieldId) {
28
- setBusy(false);
29
- return;
30
- }
26
+ useEffect(() => {
27
+ if (!locallyAvailable || !validFieldId) {
28
+ setBusy(false)
29
+ return
30
+ }
31
31
 
32
- let active = true;
33
- getLocalSecretStatus(id)
34
- .then((isReady) => {
35
- if (active) setReady(isReady);
36
- })
37
- .catch((cause: unknown) => {
38
- if (active) setError(cause instanceof Error ? cause.message : "Could not read secret status");
39
- })
40
- .finally(() => {
41
- if (active) setBusy(false);
42
- });
43
- return () => { active = false; };
44
- }, [id, locallyAvailable, validFieldId]);
32
+ let active = true
33
+ getLocalSecretStatus(id)
34
+ .then((isReady) => {
35
+ if (active) setReady(isReady)
36
+ })
37
+ .catch((cause: unknown) => {
38
+ if (active) setError(cause instanceof Error ? cause.message : 'Could not read secret status')
39
+ })
40
+ .finally(() => {
41
+ if (active) setBusy(false)
42
+ })
43
+ return () => {
44
+ active = false
45
+ }
46
+ }, [id, locallyAvailable, validFieldId])
45
47
 
46
- const feedback = ready
47
- ? `**${label}**\nSecret is ready. Field: \`${id}\`. Environment variable: \`${env}\`.\n`
48
- : "";
49
- useFeedback(`secret:${id}`, feedback, {
50
- label,
51
- required: required && locallyAvailable,
52
- });
48
+ const feedback = ready
49
+ ? `**${label}**\nSecret is ready. Field: \`${id}\`. Environment variable: \`${env}\`.\n`
50
+ : ''
51
+ useFeedback(`secret:${id}`, feedback, {
52
+ label,
53
+ required: required && locallyAvailable,
54
+ })
53
55
 
54
- const store = async () => {
55
- if (!value || !validFieldId || !validEnvName) return;
56
- setBusy(true);
57
- setError(null);
58
- try {
59
- await storeLocalSecret(id, value);
60
- setValue("");
61
- setReady(true);
62
- } catch (cause: unknown) {
63
- setError(cause instanceof Error ? cause.message : "Could not store secret");
64
- } finally {
65
- setBusy(false);
66
- }
67
- };
56
+ const store = async () => {
57
+ if (!value || !validFieldId || !validEnvName) return
58
+ setBusy(true)
59
+ setError(null)
60
+ try {
61
+ await storeLocalSecret(id, value)
62
+ setValue('')
63
+ setReady(true)
64
+ } catch (cause: unknown) {
65
+ setError(cause instanceof Error ? cause.message : 'Could not store secret')
66
+ } finally {
67
+ setBusy(false)
68
+ }
69
+ }
68
70
 
69
- const clear = async () => {
70
- setBusy(true);
71
- setError(null);
72
- try {
73
- await clearLocalSecret(id);
74
- setReady(false);
75
- } catch (cause: unknown) {
76
- setError(cause instanceof Error ? cause.message : "Could not clear secret");
77
- } finally {
78
- setBusy(false);
79
- }
80
- };
71
+ const clear = async () => {
72
+ setBusy(true)
73
+ setError(null)
74
+ try {
75
+ await clearLocalSecret(id)
76
+ setReady(false)
77
+ } catch (cause: unknown) {
78
+ setError(cause instanceof Error ? cause.message : 'Could not clear secret')
79
+ } finally {
80
+ setBusy(false)
81
+ }
82
+ }
81
83
 
82
- if (!locallyAvailable) {
83
- return (
84
- <div data-md="secretinput" data-md-label={label} className="-mx-4 px-4 py-3 my-1 rounded-lg bg-accent-amber-muted">
85
- <div className="text-[13px] font-body font-medium text-text-primary">{label}</div>
86
- <p className="text-[12px] font-body text-text-secondary mt-1">
87
- Secret input is unavailable in shared canvases. Open this runbook on the author's local canvas daemon.
88
- </p>
89
- </div>
90
- );
91
- }
84
+ if (!locallyAvailable) {
85
+ return (
86
+ <div data-md="secretinput" data-md-label={label} className="-mx-4 px-4 py-3 my-1 rounded-lg bg-accent-amber-muted">
87
+ <div className="text-[13px] font-body font-medium text-text-primary">{label}</div>
88
+ <p className="text-[12px] font-body text-text-secondary mt-1">
89
+ Secret input is unavailable in shared canvases. Open this runbook on the author's local canvas daemon.
90
+ </p>
91
+ </div>
92
+ )
93
+ }
92
94
 
93
- const configurationError = !validFieldId
94
- ? "Secret field IDs may contain letters, numbers, dots, underscores, and hyphens."
95
- : !validEnvName
96
- ? "Environment variable names must use letters, numbers, and underscores and may not start with a number."
97
- : null;
95
+ const configurationError = !validFieldId
96
+ ? 'Secret field IDs may contain letters, numbers, dots, underscores, and hyphens.'
97
+ : !validEnvName
98
+ ? 'Environment variable names must use letters, numbers, and underscores and may not start with a number.'
99
+ : null
98
100
 
99
- return (
100
- <div data-md="secretinput" data-md-label={label} className="-mx-4 px-4 py-3 my-1 rounded-lg transition-colors duration-150 hover:bg-bg-input">
101
- <div className="flex items-baseline justify-between gap-3 mb-2">
102
- <div className="flex items-baseline gap-2">
103
- <span className="text-[13px] font-body font-medium text-text-primary">{label}</span>
104
- {required && <span className="text-[10px] text-accent-red font-body">*</span>}
105
- </div>
106
- <span className={`text-[11px] font-body ${ready ? "text-accent-green" : "text-text-tertiary"}`}>
107
- {busy ? "Working…" : ready ? "Ready in memory" : "Not stored"}
108
- </span>
109
- </div>
101
+ return (
102
+ <div data-md="secretinput" data-md-label={label} className="-mx-4 px-4 py-3 my-1 rounded-lg transition-colors duration-150 hover:bg-bg-input">
103
+ <div className="flex items-baseline justify-between gap-3 mb-2">
104
+ <div className="flex items-baseline gap-2">
105
+ <span className="text-[13px] font-body font-medium text-text-primary">{label}</span>
106
+ {required && <span className="text-[10px] text-accent-red font-body">*</span>}
107
+ </div>
108
+ <span className={`text-[11px] font-body ${ready ? 'text-accent-green' : 'text-text-tertiary'}`}>
109
+ {busy ? 'Working…' : ready ? 'Ready in memory' : 'Not stored'}
110
+ </span>
111
+ </div>
110
112
 
111
- <div className="flex gap-2">
112
- <input
113
- type="password"
114
- value={value}
115
- onChange={(event) => setValue(event.target.value)}
116
- onKeyDown={(event) => {
117
- if (event.key === "Enter") {
118
- event.preventDefault();
119
- void store();
120
- }
121
- }}
122
- placeholder={placeholder || "Paste secret value"}
123
- autoComplete="off"
124
- spellCheck={false}
125
- disabled={busy || !!configurationError}
126
- className="min-w-0 flex-1 bg-bg-input text-[13px] font-mono text-text-primary rounded-lg px-3 py-2 focus:outline-none border border-border-subtle focus:border-border-hover placeholder:text-text-tertiary disabled:opacity-50 transition-colors"
127
- />
128
- <button
129
- type="button"
130
- onClick={() => void store()}
131
- disabled={busy || !value || !!configurationError}
132
- className="px-3 py-2 rounded-lg bg-btn-primary text-btn-primary-text text-[12px] font-body font-medium disabled:opacity-40 disabled:cursor-default"
133
- >
134
- {ready ? "Replace" : "Store"}
135
- </button>
136
- {ready && (
137
- <button
138
- type="button"
139
- onClick={() => void clear()}
140
- disabled={busy}
141
- className="px-3 py-2 rounded-lg border border-border-subtle text-text-secondary text-[12px] font-body font-medium hover:border-border-hover disabled:opacity-40"
142
- >
143
- Clear
144
- </button>
145
- )}
146
- </div>
113
+ <div className="flex gap-2">
114
+ <input
115
+ type="password"
116
+ value={value}
117
+ onChange={(event) => setValue(event.target.value)}
118
+ onKeyDown={(event) => {
119
+ if (event.key === 'Enter') {
120
+ event.preventDefault()
121
+ void store()
122
+ }
123
+ }}
124
+ placeholder={placeholder || 'Paste secret value'}
125
+ autoComplete="off"
126
+ spellCheck={false}
127
+ disabled={busy || !!configurationError}
128
+ className="min-w-0 flex-1 bg-bg-input text-[13px] font-mono text-text-primary rounded-lg px-3 py-2 focus:outline-none border border-border-subtle focus:border-border-hover placeholder:text-text-tertiary disabled:opacity-50 transition-colors"
129
+ />
130
+ <button
131
+ type="button"
132
+ onClick={() => void store()}
133
+ disabled={busy || !value || !!configurationError}
134
+ className="px-3 py-2 rounded-lg bg-btn-primary text-btn-primary-text text-[12px] font-body font-medium disabled:opacity-40 disabled:cursor-default"
135
+ >
136
+ {ready ? 'Replace' : 'Store'}
137
+ </button>
138
+ {ready && (
139
+ <button
140
+ type="button"
141
+ onClick={() => void clear()}
142
+ disabled={busy}
143
+ className="px-3 py-2 rounded-lg border border-border-subtle text-text-secondary text-[12px] font-body font-medium hover:border-border-hover disabled:opacity-40"
144
+ >
145
+ Clear
146
+ </button>
147
+ )}
148
+ </div>
147
149
 
148
- <p className="text-[11px] font-body text-text-tertiary mt-1.5">
149
- Stored only in daemon memory. The agent receives field {id} for {env}, not the value.
150
- </p>
151
- {(configurationError || error) && (
152
- <p className="text-[11px] text-accent-red font-body mt-1">{configurationError || error}</p>
153
- )}
154
- </div>
155
- );
150
+ <p className="text-[11px] font-body text-text-tertiary mt-1.5">
151
+ Stored only in daemon memory. The agent receives field {id} for {env}, not the value.
152
+ </p>
153
+ {(configurationError || error) && <p className="text-[11px] text-accent-red font-body mt-1">{configurationError || error}</p>}
154
+ </div>
155
+ )
156
156
  }
@@ -1,4 +1,4 @@
1
1
  // agent-canvas's canvas component set: the kernel's components plus the ones
2
2
  // only this host can back (SecretInput needs the daemon's secret endpoints).
3
- export * from "@fabrika/canvas-kernel/components";
4
- export { SecretInput } from "./SecretInput";
3
+ export * from '@fabrika/canvas-kernel/components'
4
+ export { SecretInput } from './SecretInput'