@dezycro-ai/agent-plugin 2.1.1 → 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 -782
  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 -53
  25. package/dist/hooks/lib/command-bus.js +0 -318
  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 -244
  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 -278
  50. package/dist/hooks/types.js +0 -14
  51. package/install.js +0 -84
  52. package/setup.js +0 -53
@@ -1,94 +0,0 @@
1
- /**
2
- * verify.ts — verify-evidence helpers for the pillar-1 pre-DONE gate
3
- * (TRD §5.1).
4
- *
5
- * The PreToolUse hook does NOT shell out to the verifier binary — that lives
6
- * in the `/dezycro:verify` skill. The hook's job is to detect "this path-linked
7
- * task is transitioning to DONE/PUSHED without recent passing verifier
8
- * evidence" and block with a structured message telling the agent to run
9
- * `/dezycro:verify --path <p>` first.
10
- *
11
- * Evidence source: `.dezycro/state.json` (the pre-Companion local state file
12
- * written by the V1 verify skill). Per-path coverage isn't recorded there in
13
- * V1 — any recent passing run counts as covering all paths. V2.1 should
14
- * record covered-paths explicitly.
15
- */
16
- 'use strict';
17
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- var desc = Object.getOwnPropertyDescriptor(m, k);
20
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
- desc = { enumerable: true, get: function() { return m[k]; } };
22
- }
23
- Object.defineProperty(o, k2, desc);
24
- }) : (function(o, m, k, k2) {
25
- if (k2 === undefined) k2 = k;
26
- o[k2] = m[k];
27
- }));
28
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
- Object.defineProperty(o, "default", { enumerable: true, value: v });
30
- }) : function(o, v) {
31
- o["default"] = v;
32
- });
33
- var __importStar = (this && this.__importStar) || (function () {
34
- var ownKeys = function(o) {
35
- ownKeys = Object.getOwnPropertyNames || function (o) {
36
- var ar = [];
37
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
- return ar;
39
- };
40
- return ownKeys(o);
41
- };
42
- return function (mod) {
43
- if (mod && mod.__esModule) return mod;
44
- var result = {};
45
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
- __setModuleDefault(result, mod);
47
- return result;
48
- };
49
- })();
50
- Object.defineProperty(exports, "__esModule", { value: true });
51
- exports.hasRecentPassingVerify = hasRecentPassingVerify;
52
- exports.buildBlockReason = buildBlockReason;
53
- const fs = __importStar(require("fs"));
54
- const path = __importStar(require("path"));
55
- function hasRecentPassingVerify(opts) {
56
- const o = opts || {};
57
- const repoRoot = o.repoRoot;
58
- const maxAgeMinutes = typeof o.maxAgeMinutes === 'number' ? o.maxAgeMinutes : 60;
59
- if (!repoRoot)
60
- return false;
61
- const file = path.join(repoRoot, '.dezycro', 'state.json');
62
- let parsed;
63
- try {
64
- const raw = fs.readFileSync(file, 'utf8');
65
- parsed = JSON.parse(raw);
66
- }
67
- catch {
68
- return false;
69
- }
70
- if (!parsed || typeof parsed !== 'object')
71
- return false;
72
- const lastVerifyTs = parsed.lastVerifyTs;
73
- const lastVerifyRunId = parsed.lastVerifyRunId;
74
- if (!lastVerifyTs || !lastVerifyRunId)
75
- return false;
76
- const ts = Date.parse(lastVerifyTs);
77
- if (!Number.isFinite(ts))
78
- return false;
79
- const ageMs = Date.now() - ts;
80
- if (ageMs < 0)
81
- return false;
82
- if (ageMs > maxAgeMinutes * 60 * 1000)
83
- return false;
84
- return true;
85
- }
86
- function buildBlockReason(opts) {
87
- const o = opts || {};
88
- const paths = o.paths || [];
89
- const status = o.status || 'DONE';
90
- const pathList = paths.length > 0 ? paths.join(',') : '<paths>';
91
- const reason = 'Cannot mark task ' + status + ' — no recent passing verifier run found for the linked paths. ' +
92
- 'Run `/dezycro:verify --path ' + pathList + '` first to attach passing verifier evidence, then retry.';
93
- return { reason };
94
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * workbook.ts — builds the sweep directive that the Stop hook injects into
3
- * the agent's next assistant turn (TRD §5.3.1).
4
- *
5
- * Design choice: the runner does NOT call an LLM itself. It builds a
6
- * structured directive that tells the agent to (a) scan its own recent
7
- * context per the P-1 schema, (b) for each high-confidence candidate that
8
- * passes caps + dedup, call the corresponding MCP workbook tool, and (c)
9
- * print the announce line per the template.
10
- */
11
- import type { EntityKind } from './hashing';
12
- import type { SweepDirectiveOpts } from '../types';
13
- export declare const ANNOUNCE_TEMPLATES: Readonly<Record<"decision" | "issue" | "assumption" | "task_status", string>>;
14
- /** Build the Stop-hook directive payload. */
15
- export declare function buildSweepDirective(opts: SweepDirectiveOpts): string;
16
- export declare function buildCapHitMessage(sessionAutoLogCount: number | string): string;
17
- /**
18
- * Detect the entityKind from a tool name string. Returns null if not a
19
- * tracked workbook tool.
20
- */
21
- export declare function entityKindForTool(toolName: string | null | undefined): EntityKind | null;
@@ -1,77 +0,0 @@
1
- /**
2
- * workbook.ts — builds the sweep directive that the Stop hook injects into
3
- * the agent's next assistant turn (TRD §5.3.1).
4
- *
5
- * Design choice: the runner does NOT call an LLM itself. It builds a
6
- * structured directive that tells the agent to (a) scan its own recent
7
- * context per the P-1 schema, (b) for each high-confidence candidate that
8
- * passes caps + dedup, call the corresponding MCP workbook tool, and (c)
9
- * print the announce line per the template.
10
- */
11
- 'use strict';
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.ANNOUNCE_TEMPLATES = void 0;
14
- exports.buildSweepDirective = buildSweepDirective;
15
- exports.buildCapHitMessage = buildCapHitMessage;
16
- exports.entityKindForTool = entityKindForTool;
17
- exports.ANNOUNCE_TEMPLATES = Object.freeze({
18
- decision: "Logging decision: {{summary}} — reason: {{reason}}. Say 'undo that' if wrong.",
19
- issue: "Logging issue ({{severity}}): {{summary}}. Say 'undo that' if wrong.",
20
- assumption: "Logging assumption: {{summary}} — rationale: {{rationale}}. Say 'undo that' if wrong.",
21
- task_status: "Marking task {{task_id}} as {{proposed_status}} — rationale: {{rationale}}. Say 'undo that' if wrong.",
22
- });
23
- const CAP_HIT_MESSAGE = "Auto-logging paused — {{count}} entries logged this session. Type /dezycro:sync to log manually.";
24
- /** Build the Stop-hook directive payload. */
25
- function buildSweepDirective(opts) {
26
- const t = opts.thresholds || {};
27
- const turnLeft = Math.max(0, Number(opts.perTurnSlotsLeft) || 0);
28
- const sessionLeft = Math.max(0, Number(opts.perSessionSlotsLeft) || 0);
29
- if (turnLeft <= 0 || sessionLeft <= 0) {
30
- return CAP_HIT_MESSAGE.replace('{{count}}', String(sessionLeft <= 0 ? 'session-cap' : 'turn-cap'));
31
- }
32
- const slotsLeft = Math.min(turnLeft, sessionLeft);
33
- const ring = (opts.recentHashes || []).filter(Boolean);
34
- const lines = [
35
- '[Dezycro Companion]',
36
- `Feature: ${formatFeature(opts.activeFeatureName, opts.activeFeatureId)}. Slots: ${slotsLeft} (${turnLeft}/turn, ${sessionLeft}/session).`,
37
- '',
38
- `Scan since your last message for committed signals to log:`,
39
- ` - Decision (conf \u2265 ${t.decision ?? 0.85}) — committed technical/product choice`,
40
- ` - Issue (conf \u2265 ${t.issue ?? 0.80}) — current blocker/bug`,
41
- ` - Assumption (conf \u2265 ${t.assumption ?? 0.90}) — unverified belief affecting impl`,
42
- ` - Task-status (conf \u2265 ${t.taskStatus ?? 0.90}) — task is now DONE/PUSHED`,
43
- '',
44
- 'Skip: hypotheticals, brainstorming, implementation-obvious details, ephemeral content, intent statements while authoring a PRD/TRD.',
45
- ];
46
- if (ring.length > 0) {
47
- lines.push(`Already-logged hashes (skip dupes): ${ring.join(', ')}`);
48
- }
49
- lines.push('', 'For each surviving candidate (max ' + slotsLeft + '): print the announce line verbatim and call the matching MCP tool.', ' decision: "' + exports.ANNOUNCE_TEMPLATES.decision + '" \u2192 mcp__dezycro(-dev)?__add_decision', ' issue: "' + exports.ANNOUNCE_TEMPLATES.issue + '" \u2192 mcp__dezycro(-dev)?__add_issue', ' assumption: "' + exports.ANNOUNCE_TEMPLATES.assumption + '" \u2192 mcp__dezycro(-dev)?__add_assumption', ' task_status: "' + exports.ANNOUNCE_TEMPLATES.task_status + '" \u2192 mcp__dezycro(-dev)?__update_task', '', 'If nothing meets the bar, simply continue with whatever the user asked next — do NOT output any acknowledgment line. The hook will silence itself for trivial turns.');
50
- return lines.join('\n');
51
- }
52
- function formatFeature(name, id) {
53
- if (!id)
54
- return '(none — skip if no feature is active)';
55
- const shortId = String(id).slice(0, 8);
56
- return name ? `${name} (${shortId}\u2026)` : shortId + '\u2026';
57
- }
58
- function buildCapHitMessage(sessionAutoLogCount) {
59
- return CAP_HIT_MESSAGE.replace('{{count}}', String(sessionAutoLogCount));
60
- }
61
- /**
62
- * Detect the entityKind from a tool name string. Returns null if not a
63
- * tracked workbook tool.
64
- */
65
- function entityKindForTool(toolName) {
66
- if (typeof toolName !== 'string')
67
- return null;
68
- if (/add_decision$/.test(toolName))
69
- return 'decision';
70
- if (/add_issue$/.test(toolName))
71
- return 'issue';
72
- if (/add_assumption$/.test(toolName))
73
- return 'assumption';
74
- if (/update_task$/.test(toolName))
75
- return 'task-status';
76
- return null;
77
- }
@@ -1,278 +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
- export interface CommandBusState {
211
- cursor: string | null;
212
- lastPollTs: string | null;
213
- consecutiveFailures: number;
214
- recentEventIds: string[];
215
- }
216
- export interface InboxEvent {
217
- eventId: string;
218
- featureId: string;
219
- eventType: string;
220
- sourceType: string;
221
- sourceId: string | null;
222
- urgency: 'BLOCKING' | 'INFORMATIONAL';
223
- payload: Record<string, unknown>;
224
- createdTs: string;
225
- ttlAt: string;
226
- issuerType: string;
227
- issuerId: string | null;
228
- }
229
- export interface CompanionConfig {
230
- companion?: {
231
- autoVerify?: AutoVerifyConfig;
232
- autoWorkbookUpdates?: AutoWorkbookUpdatesConfig;
233
- coverageNudges?: CoverageNudgesConfig;
234
- authoring?: AuthoringConfig;
235
- commandBus?: CommandBusConfig;
236
- safeMode?: boolean;
237
- };
238
- }
239
- export interface Thresholds {
240
- decision: number;
241
- issue: number;
242
- assumption: number;
243
- taskStatus: number;
244
- }
245
- export interface ActiveFeature {
246
- featureId: string | null;
247
- featureName: string | null;
248
- }
249
- export interface SweepDirectiveOpts {
250
- thresholds: Thresholds;
251
- perTurnSlotsLeft: number;
252
- perSessionSlotsLeft: number;
253
- recentHashes: string[];
254
- activeFeatureId: string | null;
255
- activeFeatureName: string | null;
256
- }
257
- export interface ReversalDirective {
258
- tool: 'update_decision' | 'update_issue' | 'update_task';
259
- args: Record<string, unknown>;
260
- humanLine: string;
261
- }
262
- export type HookEvent = 'session-start' | 'user-prompt-submit' | 'pre-tool-use' | 'post-tool-use' | 'stop' | 'state' | 'authoring-state';
263
- export interface RouterInvocation {
264
- event: HookEvent | null;
265
- route: string | null;
266
- payload: unknown;
267
- flags: Record<string, string | boolean>;
268
- }
269
- export interface QualityGateBlockingIssue {
270
- section: string;
271
- issue: string;
272
- required_fix: string;
273
- }
274
- export interface QualityGateResult {
275
- passed: boolean;
276
- blockingIssues: QualityGateBlockingIssue[];
277
- }
278
- 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
- });