@dezycro-ai/agent-plugin 2.1.2 → 2.2.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 (52) hide show
  1. package/README.md +14 -98
  2. package/dist/cli/dezycro.js +50 -0
  3. package/dist/cli/install.js +7 -0
  4. package/dist/dezycro-config.d.ts +52 -0
  5. package/dist/dezycro-config.js +167 -0
  6. package/dist/gateway/compact-cli.js +8 -0
  7. package/dist/gateway/proxy.js +35 -0
  8. package/dist/hooks/lib/router.js +14 -830
  9. package/dist/schemas/anthropic.d.ts +119 -0
  10. package/dist/schemas/anthropic.js +43 -0
  11. package/dist/schemas/dezycro.d.ts +19 -0
  12. package/dist/schemas/dezycro.js +22 -0
  13. package/dist/schemas/gateway.d.ts +40 -0
  14. package/dist/schemas/gateway.js +30 -0
  15. package/dist/schemas/gating.d.ts +32 -0
  16. package/dist/schemas/gating.js +15 -0
  17. package/dist/schemas/index.d.ts +14 -0
  18. package/dist/schemas/index.js +29 -0
  19. package/package.json +21 -13
  20. package/LICENSE +0 -18
  21. package/bin/resolve-auth.js +0 -112
  22. package/dist/hooks/lib/authoring.d.ts +0 -118
  23. package/dist/hooks/lib/authoring.js +0 -277
  24. package/dist/hooks/lib/command-bus.d.ts +0 -66
  25. package/dist/hooks/lib/command-bus.js +0 -357
  26. package/dist/hooks/lib/config.d.ts +0 -28
  27. package/dist/hooks/lib/config.js +0 -175
  28. package/dist/hooks/lib/controller-match.d.ts +0 -16
  29. package/dist/hooks/lib/controller-match.js +0 -96
  30. package/dist/hooks/lib/coverage.d.ts +0 -17
  31. package/dist/hooks/lib/coverage.js +0 -66
  32. package/dist/hooks/lib/hashing.d.ts +0 -8
  33. package/dist/hooks/lib/hashing.js +0 -49
  34. package/dist/hooks/lib/logging.d.ts +0 -13
  35. package/dist/hooks/lib/logging.js +0 -72
  36. package/dist/hooks/lib/publish-spec.d.ts +0 -17
  37. package/dist/hooks/lib/publish-spec.js +0 -64
  38. package/dist/hooks/lib/quality-gate.d.ts +0 -67
  39. package/dist/hooks/lib/quality-gate.js +0 -187
  40. package/dist/hooks/lib/router.d.ts +0 -32
  41. package/dist/hooks/lib/state.d.ts +0 -34
  42. package/dist/hooks/lib/state.js +0 -245
  43. package/dist/hooks/lib/undo.d.ts +0 -11
  44. package/dist/hooks/lib/undo.js +0 -71
  45. package/dist/hooks/lib/verify.d.ts +0 -28
  46. package/dist/hooks/lib/verify.js +0 -94
  47. package/dist/hooks/lib/workbook.d.ts +0 -21
  48. package/dist/hooks/lib/workbook.js +0 -77
  49. package/dist/hooks/types.d.ts +0 -293
  50. package/dist/hooks/types.js +0 -14
  51. package/install.js +0 -84
  52. package/setup.js +0 -53
@@ -1,293 +0,0 @@
1
- /**
2
- * types.ts — shared type definitions for Companion V2 hooks.
3
- *
4
- * Hook output types match Claude Code's documented schema (captured from
5
- * the schema error message hit in the V2.0 dogfood — Anthropic does not
6
- * publish official TS types as of 2026-05). Hook input payload types are
7
- * partials because Claude Code's payload shape varies per event and we
8
- * only consume the fields we use.
9
- *
10
- * Companion state and config match the on-disk JSON shape in
11
- * `.dezycro/companion-state.json` and `.dezycro/config.json`.
12
- */
13
- export type HookEventName = 'PreToolUse' | 'PostToolUse' | 'UserPromptSubmit' | 'Stop' | 'SessionStart' | 'SessionEnd' | 'PreCompact' | 'Notification' | 'SubagentStop';
14
- export type Decision = 'approve' | 'block';
15
- export type PermissionDecision = 'allow' | 'deny' | 'ask' | 'defer';
16
- /** Fields valid at the top level of every hook output. */
17
- interface HookOutputCommon {
18
- continue?: boolean;
19
- suppressOutput?: boolean;
20
- stopReason?: string;
21
- decision?: Decision;
22
- reason?: string;
23
- systemMessage?: string;
24
- permissionDecision?: PermissionDecision;
25
- }
26
- /** PreToolUse: also accepts a hookSpecificOutput with PreToolUse fields. */
27
- export interface PreToolUseHookOutput extends HookOutputCommon {
28
- hookSpecificOutput?: {
29
- hookEventName: 'PreToolUse';
30
- permissionDecision?: PermissionDecision;
31
- permissionDecisionReason?: string;
32
- updatedInput?: Record<string, unknown>;
33
- };
34
- }
35
- /** PostToolUse: optional additionalContext to inject into the next turn. */
36
- export interface PostToolUseHookOutput extends HookOutputCommon {
37
- hookSpecificOutput?: {
38
- hookEventName: 'PostToolUse';
39
- additionalContext?: string;
40
- };
41
- }
42
- /** UserPromptSubmit: additionalContext REQUIRED if hookSpecificOutput is set. */
43
- export interface UserPromptSubmitHookOutput extends HookOutputCommon {
44
- hookSpecificOutput?: {
45
- hookEventName: 'UserPromptSubmit';
46
- additionalContext: string;
47
- };
48
- }
49
- /** Stop: no hookSpecificOutput. Only top-level fields are valid. */
50
- export type StopHookOutput = HookOutputCommon;
51
- /** SessionStart / SessionEnd / etc: top-level only (no hookSpecificOutput). */
52
- export type SessionStartHookOutput = HookOutputCommon;
53
- export type AnyHookOutput = PreToolUseHookOutput | PostToolUseHookOutput | UserPromptSubmitHookOutput | StopHookOutput | SessionStartHookOutput;
54
- export interface PreToolUsePayload {
55
- tool_name?: string;
56
- tool_input?: Record<string, unknown>;
57
- session_id?: string;
58
- transcript_path?: string;
59
- }
60
- export interface PostToolUsePayload {
61
- tool_name?: string;
62
- tool_input?: Record<string, unknown>;
63
- tool_response?: Record<string, unknown>;
64
- response?: Record<string, unknown>;
65
- session_id?: string;
66
- transcript_path?: string;
67
- }
68
- export interface UserPromptSubmitPayload {
69
- prompt?: string;
70
- user_message?: string;
71
- message?: string;
72
- session_id?: string;
73
- }
74
- export interface StopPayload {
75
- session_id?: string;
76
- transcript_path?: string;
77
- }
78
- export interface SessionStartPayload {
79
- session_id?: string;
80
- }
81
- export interface ControllerEdit {
82
- path: string;
83
- editedTs: string;
84
- }
85
- export interface CoverageSnapshot {
86
- uncoveredPaths?: number;
87
- endpointsNotInSpec?: number;
88
- staleBaselines?: number;
89
- surfacedTs?: string | null;
90
- previous?: CoverageSnapshot | null;
91
- [extra: string]: unknown;
92
- }
93
- export interface LastAutoWorkbookMutation {
94
- /** Bare tool name, e.g. "add_decision" / "update_task" (no mcp__ prefix). */
95
- tool: string;
96
- entityId: string | null;
97
- createdInTurnId: number;
98
- createdTs: string;
99
- /** Only set for update_task — the status to restore on undo. */
100
- priorStatus: string | null;
101
- }
102
- export interface CompanionMetrics {
103
- autoDecisionLogs: number;
104
- autoIssueLogs: number;
105
- autoAssumptionLogs: number;
106
- autoTaskStatusLogs: number;
107
- undoCount: number;
108
- verifyAutoRuns: number;
109
- verifyAutoFailures: number;
110
- qualityGateFailures: number;
111
- contextGateFailures: number;
112
- lockContention: number;
113
- forceApprovals: number;
114
- }
115
- export interface CompanionState {
116
- schemaVersion: number;
117
- currentSessionId: string | null;
118
- authoringMode: boolean;
119
- authoringDocId: string | null;
120
- authoringDocType: 'PRD' | 'TRD' | null;
121
- authoringTranscriptPath: string | null;
122
- authoringStartedTs: string | null;
123
- pulseCount: number;
124
- lastEditTs: string | null;
125
- needsSpecPublish: boolean;
126
- controllerEditsSinceLastPublish: ControllerEdit[];
127
- coverageSnapshot: CoverageSnapshot | null;
128
- coverageSnapshotTs: string | null;
129
- coverageFetchPending: boolean;
130
- lastVerifyCompletionTs: string | null;
131
- recentDecisionHashes: string[];
132
- recentIssueHashes: string[];
133
- recentAssumptionHashes: string[];
134
- lastAutoWorkbookMutation: LastAutoWorkbookMutation | null;
135
- sessionAutoLogCount: number;
136
- turnAutoLogCount: number;
137
- currentTurnId: number;
138
- suppressWorkbookUpdatesUntil: string | null;
139
- pendingWorkbookSweep: boolean;
140
- pendingWorkbookSweepReason: string | null;
141
- lastSeenVerifyCompletionTs: string | null;
142
- commandBus: CommandBusState;
143
- metrics: CompanionMetrics;
144
- }
145
- /**
146
- * Patch shape for state.patch() — partial state + convenience "push" keys
147
- * that append to the corresponding ring buffer instead of replacing it.
148
- * `metrics` overrides the full-CompanionState definition to be partial.
149
- */
150
- export type StatePatch = Partial<Omit<CompanionState, 'metrics'>> & {
151
- metrics?: Partial<CompanionMetrics>;
152
- pushDecisionHash?: string;
153
- pushIssueHash?: string;
154
- pushAssumptionHash?: string;
155
- pushControllerEdit?: ControllerEdit;
156
- };
157
- export interface PostEditPulseConfig {
158
- enabled?: boolean;
159
- threshold?: number;
160
- }
161
- export interface AutoVerifyConfig {
162
- preTaskDone?: boolean;
163
- prePush?: boolean;
164
- postEditPulse?: PostEditPulseConfig;
165
- autoPublishSpecOnControllerChange?: boolean;
166
- controllerPaths?: string[];
167
- verifyTimeoutSeconds?: number;
168
- publishSpecTimeoutSeconds?: number;
169
- }
170
- export interface ThresholdOverrides {
171
- decision?: number | null;
172
- issue?: number | null;
173
- assumption?: number | null;
174
- taskStatus?: number | null;
175
- }
176
- export type PresetName = 'conservative' | 'balanced' | 'aggressive';
177
- export interface AutoWorkbookUpdatesConfig {
178
- enabled?: boolean;
179
- preset?: PresetName;
180
- maxAutoLogsPerTurn?: number;
181
- maxAutoLogsPerSession?: number;
182
- undoWindow?: 'next-turn' | string;
183
- thresholds?: ThresholdOverrides;
184
- trivialTurnCharCutoff?: number;
185
- hashRingBufferSize?: number;
186
- }
187
- export interface CoverageNudgesConfig {
188
- enabled?: boolean;
189
- staleBaselineDays?: number;
190
- fetchMode?: 'async' | 'sync' | 'off';
191
- }
192
- export interface AuthoringConfig {
193
- defaultDepth?: 'adaptive' | 'shallow' | 'deep';
194
- existingWorkScan?: boolean;
195
- qualityGate?: {
196
- enabled?: boolean;
197
- };
198
- minViableContextGate?: {
199
- enabled?: boolean;
200
- };
201
- }
202
- export type CommandBusHook = 'sessionStart' | 'userPromptSubmit' | 'stop' | 'postToolUse';
203
- export type CommandBusReactionMode = 'HALT_AND_REPLAN' | 'ACKNOWLEDGE_AND_CONTINUE' | 'SILENT_LOG';
204
- export interface CommandBusConfig {
205
- enabled?: boolean;
206
- pollHooks?: CommandBusHook[];
207
- minPollIntervalSeconds?: number;
208
- reactionMode?: CommandBusReactionMode;
209
- /**
210
- * After this many consecutive poll failures the effective poll interval grows
211
- * exponentially (backoff) so an unreachable inbox endpoint stops being polled
212
- * on every hook fire. Defaults to 3.
213
- */
214
- circuitBreakerThreshold?: number;
215
- /** Upper bound (seconds) on the backed-off poll interval. Defaults to 1800 (30m). */
216
- maxBackoffSeconds?: number;
217
- }
218
- export interface CommandBusState {
219
- cursor: string | null;
220
- /** Timestamp of the last SUCCESSFUL poll (server clock). Used as the dedup/cursor anchor. */
221
- lastPollTs: string | null;
222
- /**
223
- * Timestamp of the last poll ATTEMPT (success or failure, client clock). The
224
- * min-interval / backoff floor is measured from here so repeated failures are
225
- * throttled even before a first success exists.
226
- */
227
- lastAttemptTs?: string | null;
228
- consecutiveFailures: number;
229
- recentEventIds: string[];
230
- }
231
- export interface InboxEvent {
232
- eventId: string;
233
- featureId: string;
234
- eventType: string;
235
- sourceType: string;
236
- sourceId: string | null;
237
- urgency: 'BLOCKING' | 'INFORMATIONAL';
238
- payload: Record<string, unknown>;
239
- createdTs: string;
240
- ttlAt: string;
241
- issuerType: string;
242
- issuerId: string | null;
243
- }
244
- export interface CompanionConfig {
245
- companion?: {
246
- autoVerify?: AutoVerifyConfig;
247
- autoWorkbookUpdates?: AutoWorkbookUpdatesConfig;
248
- coverageNudges?: CoverageNudgesConfig;
249
- authoring?: AuthoringConfig;
250
- commandBus?: CommandBusConfig;
251
- safeMode?: boolean;
252
- };
253
- }
254
- export interface Thresholds {
255
- decision: number;
256
- issue: number;
257
- assumption: number;
258
- taskStatus: number;
259
- }
260
- export interface ActiveFeature {
261
- featureId: string | null;
262
- featureName: string | null;
263
- }
264
- export interface SweepDirectiveOpts {
265
- thresholds: Thresholds;
266
- perTurnSlotsLeft: number;
267
- perSessionSlotsLeft: number;
268
- recentHashes: string[];
269
- activeFeatureId: string | null;
270
- activeFeatureName: string | null;
271
- }
272
- export interface ReversalDirective {
273
- tool: 'update_decision' | 'update_issue' | 'update_task';
274
- args: Record<string, unknown>;
275
- humanLine: string;
276
- }
277
- export type HookEvent = 'session-start' | 'user-prompt-submit' | 'pre-tool-use' | 'post-tool-use' | 'stop' | 'state' | 'authoring-state';
278
- export interface RouterInvocation {
279
- event: HookEvent | null;
280
- route: string | null;
281
- payload: unknown;
282
- flags: Record<string, string | boolean>;
283
- }
284
- export interface QualityGateBlockingIssue {
285
- section: string;
286
- issue: string;
287
- required_fix: string;
288
- }
289
- export interface QualityGateResult {
290
- passed: boolean;
291
- blockingIssues: QualityGateBlockingIssue[];
292
- }
293
- export {};
@@ -1,14 +0,0 @@
1
- /**
2
- * types.ts — shared type definitions for Companion V2 hooks.
3
- *
4
- * Hook output types match Claude Code's documented schema (captured from
5
- * the schema error message hit in the V2.0 dogfood — Anthropic does not
6
- * publish official TS types as of 2026-05). Hook input payload types are
7
- * partials because Claude Code's payload shape varies per event and we
8
- * only consume the fields we use.
9
- *
10
- * Companion state and config match the on-disk JSON shape in
11
- * `.dezycro/companion-state.json` and `.dezycro/config.json`.
12
- */
13
- 'use strict';
14
- Object.defineProperty(exports, "__esModule", { value: true });
package/install.js DELETED
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
- const os = require("os");
6
-
7
- const HOME = os.homedir();
8
- const commandsDir = path.join(HOME, ".claude", "commands", "dezycro");
9
- const skillsDir = path.join(__dirname, "skills");
10
- const settingsPath = path.join(HOME, ".claude", "settings.json");
11
- const hooksJsonPath = path.join(__dirname, "hooks", "hooks.json");
12
- const runnerPath = path.join(__dirname, "hooks", "companion-runner");
13
-
14
- fs.mkdirSync(commandsDir, { recursive: true });
15
-
16
- const skills = fs
17
- .readdirSync(skillsDir, { withFileTypes: true })
18
- .filter((d) => d.isDirectory() && fs.existsSync(path.join(skillsDir, d.name, "SKILL.md")))
19
- .map((d) => d.name);
20
-
21
- for (const name of skills) {
22
- const src = path.join(skillsDir, name, "SKILL.md");
23
- const dst = path.join(commandsDir, `${name}.md`);
24
- fs.copyFileSync(src, dst);
25
- }
26
-
27
- let hooksInstalled = false;
28
- let hooksAlreadyPresent = false;
29
- try {
30
- const hooksConfig = JSON.parse(fs.readFileSync(hooksJsonPath, "utf8"));
31
- const incoming = inlinePluginRoot(hooksConfig.hooks || {}, __dirname);
32
-
33
- let existing = { hooks: {} };
34
- if (fs.existsSync(settingsPath)) {
35
- try { existing = JSON.parse(fs.readFileSync(settingsPath, "utf8")); }
36
- catch { existing = { hooks: {} }; }
37
- }
38
- if (!existing.hooks) existing.hooks = {};
39
-
40
- const before = JSON.stringify(existing.hooks);
41
- for (const event of Object.keys(incoming)) {
42
- const existingEntries = Array.isArray(existing.hooks[event]) ? existing.hooks[event] : [];
43
- const filtered = existingEntries.filter((e) => !isDezycroEntry(e));
44
- existing.hooks[event] = [...filtered, ...incoming[event]];
45
- }
46
- const after = JSON.stringify(existing.hooks);
47
-
48
- if (before === after) {
49
- hooksAlreadyPresent = true;
50
- } else {
51
- fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
52
- fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
53
- hooksInstalled = true;
54
- }
55
-
56
- try { fs.chmodSync(runnerPath, 0o755); } catch {}
57
- } catch (err) {
58
- console.log(`\n ⚠ Could not install V2 hooks automatically: ${err.message}`);
59
- console.log(` Hooks config: ${hooksJsonPath}`);
60
- console.log(` Merge it into ${settingsPath} manually, or install as a Claude Code plugin.`);
61
- }
62
-
63
- console.log(`\n ✓ Dezycro commands installed (${skills.length}) to ~/.claude/commands/dezycro/`);
64
- console.log(` ${skills.map((s) => `/dezycro:${s}`).join(", ")}`);
65
- if (hooksInstalled) {
66
- console.log(` ✓ Companion V2 hooks merged into ~/.claude/settings.json`);
67
- } else if (hooksAlreadyPresent) {
68
- console.log(` ✓ Companion V2 hooks already present in ~/.claude/settings.json`);
69
- }
70
- console.log(`\n Next: npx dezycro-setup`);
71
- console.log(` Then: /dezycro:import-features\n`);
72
-
73
- function inlinePluginRoot(hooks, root) {
74
- return JSON.parse(JSON.stringify(hooks, (k, v) => {
75
- if (typeof v === "string") return v.replace(/"?\$\{CLAUDE_PLUGIN_ROOT\}"?/g, root);
76
- return v;
77
- }));
78
- }
79
-
80
- function isDezycroEntry(entry) {
81
- if (!entry || typeof entry !== "object") return false;
82
- const hooks = Array.isArray(entry.hooks) ? entry.hooks : [];
83
- return hooks.some((h) => h && typeof h.command === "string" && h.command.includes("/hooks/companion-runner"));
84
- }
package/setup.js DELETED
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const { execSync } = require("child_process");
4
- const fs = require("fs");
5
- const os = require("os");
6
- const path = require("path");
7
- const readline = require("readline");
8
-
9
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10
-
11
- console.log(`\n Dezycro Setup`);
12
- console.log(` Get your API key from Dezycro → Settings → API Keys\n`);
13
-
14
- rl.question(" API key (dzy_...): ", (apiKey) => {
15
- apiKey = (apiKey || "").trim();
16
-
17
- if (!apiKey || !apiKey.startsWith("dzy_")) {
18
- console.log(`\n Invalid key. Must start with dzy_\n`);
19
- rl.close();
20
- process.exit(1);
21
- }
22
-
23
- const mcpUrl = "https://mcp.dezycro.ai";
24
-
25
- // 1. Configure Claude Code MCP server.
26
- try {
27
- execSync(
28
- `claude mcp add --transport http dezycro "${mcpUrl}/mcp" --header "Authorization: Bearer ${apiKey}"`,
29
- { stdio: "inherit" }
30
- );
31
- console.log(`\n ✓ Dezycro MCP configured`);
32
- } catch (err) {
33
- console.error(`\n Failed to configure MCP. Run manually:`);
34
- console.error(` claude mcp add --transport http dezycro "${mcpUrl}/mcp" --header "Authorization: Bearer ${apiKey}"\n`);
35
- }
36
-
37
- // 2. Save the user-global Companion token so companion-runner can poll the
38
- // Agent Command Bus without per-repo config. Project-local
39
- // .dezycro/companion-token.local.json still overrides this.
40
- try {
41
- const globalDir = path.join(os.homedir(), ".dezycro");
42
- const globalTokenPath = path.join(globalDir, "token.json");
43
- fs.mkdirSync(globalDir, { recursive: true, mode: 0o700 });
44
- fs.writeFileSync(globalTokenPath, JSON.stringify({ token: apiKey }, null, 2), { mode: 0o600 });
45
- console.log(` ✓ Companion token saved to ${globalTokenPath}`);
46
- } catch (err) {
47
- console.error(` Failed to save companion token: ${err.message}`);
48
- console.error(` Drop it manually at ~/.dezycro/token.json: {"token": "${apiKey}"}\n`);
49
- }
50
-
51
- console.log(`\n You're all set! In Claude Code run: /dezycro:import-features\n`);
52
- rl.close();
53
- });