orca-opencode-plugin 1.1.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.
- package/README.md +189 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +179 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Orca OpenCode Plugin
|
|
2
|
+
|
|
3
|
+
OpenCode plugin wrapper for Orca runtime guardrails.
|
|
4
|
+
|
|
5
|
+
## What this plugin does
|
|
6
|
+
|
|
7
|
+
This plugin adds Orca-native lifecycle hooks to OpenCode. It lets OpenCode call the Orca CLI for policy checks, audit logging, and runtime safety decisions without duplicating policy logic.
|
|
8
|
+
|
|
9
|
+
The plugin is a thin integration layer. The Orca CLI remains the source of truth for all policy decisions.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
- Orca CLI built and available in PATH (run `orca doctor` to verify)
|
|
14
|
+
- OpenCode host installed
|
|
15
|
+
|
|
16
|
+
Orca must be installed separately. The plugin does not bundle the Orca CLI.
|
|
17
|
+
|
|
18
|
+
## Install from npm
|
|
19
|
+
|
|
20
|
+
Add to your `opencode.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"$schema": "https://opencode.ai/config.json",
|
|
25
|
+
"plugin": ["orca-opencode-plugin"]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then install dependencies:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install orca-opencode-plugin
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The strongest local protection remains running OpenCode through `orca run -- opencode`; the OpenCode plugin provides native hooks and guardrails inside OpenCode.
|
|
36
|
+
|
|
37
|
+
## Install from local path
|
|
38
|
+
|
|
39
|
+
If you prefer to use the plugin directly from the Orca repository:
|
|
40
|
+
|
|
41
|
+
### Project-local install
|
|
42
|
+
|
|
43
|
+
Copy or symlink this directory into your project:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# From the Orca repo root
|
|
47
|
+
mkdir -p .opencode/plugins
|
|
48
|
+
cp integrations/opencode-plugin/orca.ts .opencode/plugins/orca.ts
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
See `examples/project-plugin-path.md` for details.
|
|
52
|
+
|
|
53
|
+
### Global install
|
|
54
|
+
|
|
55
|
+
Copy or symlink to the OpenCode global plugins directory:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
mkdir -p ~/.config/opencode/plugins
|
|
59
|
+
cp integrations/opencode-plugin/orca.ts ~/.config/opencode/plugins/orca.ts
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
See `examples/global-plugin-path.md` for details.
|
|
63
|
+
|
|
64
|
+
### Verify the plugin is recognized
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
orca plugin doctor opencode
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Verify install
|
|
71
|
+
|
|
72
|
+
Run the Orca plugin doctor:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
orca plugin doctor opencode
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Expected output sections:
|
|
79
|
+
- Orca version
|
|
80
|
+
- Policy status (present/valid)
|
|
81
|
+
- Plugin directories (opencode: found)
|
|
82
|
+
- Host binaries (opencode: detected or not detected)
|
|
83
|
+
|
|
84
|
+
## Hooks included
|
|
85
|
+
|
|
86
|
+
The plugin registers lifecycle hooks that call `orca hook opencode <event>`:
|
|
87
|
+
|
|
88
|
+
| Event | When it fires | Behavior |
|
|
89
|
+
|-------|---------------|----------|
|
|
90
|
+
| `session.created` | At the start of an OpenCode session | Informational (readiness log) |
|
|
91
|
+
| `tool.execute.before` | Before OpenCode invokes a tool | **Blocking** — Orca can prevent the tool call |
|
|
92
|
+
| `tool.execute.after` | After OpenCode finishes using a tool | Informational (audit only) |
|
|
93
|
+
| `permission.asked` | When OpenCode requests user permission | **Blocking** — Orca can deny the permission |
|
|
94
|
+
| `file.edited` | When a file is edited by OpenCode | Informational (audit only) |
|
|
95
|
+
| `command.executed` | When a shell command is executed | Informational (audit only) |
|
|
96
|
+
| `session.updated` | When the session state changes | Informational (audit only) |
|
|
97
|
+
| `session.idle` | When the session becomes idle | Informational (audit only) |
|
|
98
|
+
| `session.error` | When a session error occurs | Informational (audit only) |
|
|
99
|
+
| `shell.env` | When the shell environment is read | Informational (secrets redacted) |
|
|
100
|
+
|
|
101
|
+
## How hooks call Orca
|
|
102
|
+
|
|
103
|
+
Each hook sends a JSON payload to `orca hook opencode <event>` via stdin and reads a JSON decision from stdout. The plugin preserves OpenCode's expected return values. Human-readable logs go to stderr.
|
|
104
|
+
|
|
105
|
+
Example payload for `tool.execute.before`:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"version": 1,
|
|
110
|
+
"host": "opencode",
|
|
111
|
+
"event": "PreToolUse",
|
|
112
|
+
"payload": {
|
|
113
|
+
"tool": "shell",
|
|
114
|
+
"command": "git status"
|
|
115
|
+
},
|
|
116
|
+
"session_id": "session-uuid",
|
|
117
|
+
"timestamp": "2026-01-01T00:00:00Z"
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Example response:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"version": 1,
|
|
126
|
+
"decision": "allow",
|
|
127
|
+
"risk": "low",
|
|
128
|
+
"category": "command",
|
|
129
|
+
"reason": "policy_allow",
|
|
130
|
+
"message": "Allowed by policy"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
If the decision is `block`, the plugin throws an error that prevents the tool from executing.
|
|
135
|
+
|
|
136
|
+
## Run redteam
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
orca redteam --ci
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Replay sessions
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
orca replay --session last --verify
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Uninstall
|
|
149
|
+
|
|
150
|
+
Remove the plugin from your OpenCode configuration:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# npm package
|
|
154
|
+
npm uninstall orca-opencode-plugin
|
|
155
|
+
|
|
156
|
+
# Project-local file
|
|
157
|
+
rm .opencode/plugins/orca.ts
|
|
158
|
+
|
|
159
|
+
# Global file
|
|
160
|
+
rm ~/.config/opencode/plugins/orca.ts
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This plugin does not mutate host configuration, so uninstalling is safe.
|
|
164
|
+
|
|
165
|
+
## Known limitations
|
|
166
|
+
|
|
167
|
+
- Hooks are advisory for informational events; blocking hooks depend on OpenCode honoring thrown errors.
|
|
168
|
+
- The strongest protection remains `orca run -- opencode`.
|
|
169
|
+
- Plugin installation depends on OpenCode version and plugin loading mechanism.
|
|
170
|
+
- No telemetry is collected.
|
|
171
|
+
- Official npm publication is in progress; the package structure is ready for publication.
|
|
172
|
+
|
|
173
|
+
## Security model
|
|
174
|
+
|
|
175
|
+
- This plugin calls the Orca CLI; it does not reimplement policy logic.
|
|
176
|
+
- No raw secrets are persisted in plugin files.
|
|
177
|
+
- Secrets are redacted from payloads before sending to Orca (keys matching `password`, `token`, `secret`, `api_key`, etc. are replaced with `[REDACTED]`).
|
|
178
|
+
- Hook return values remain valid for OpenCode parsing.
|
|
179
|
+
- Human logs go to stderr.
|
|
180
|
+
- CI mode never prompts.
|
|
181
|
+
- This plugin does not claim stronger enforcement than OpenCode hooks support.
|
|
182
|
+
|
|
183
|
+
## No MCP server behavior
|
|
184
|
+
|
|
185
|
+
The OpenCode plugin does not add MCP server behavior or drone-specific plugin features.
|
|
186
|
+
|
|
187
|
+
## Strongest protection warning
|
|
188
|
+
|
|
189
|
+
> The Orca OpenCode plugin adds lifecycle hooks for OpenCode. For the strongest local protection, run the OpenCode process itself through Orca with `orca run -- opencode`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface OpenCodeContext {
|
|
2
|
+
hooks: {
|
|
3
|
+
on: (event: string, handler: (data: unknown) => unknown | Promise<unknown>) => void;
|
|
4
|
+
};
|
|
5
|
+
shell?: {
|
|
6
|
+
$: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<{
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
exitCode: number;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
logger?: {
|
|
13
|
+
info: (msg: string) => void;
|
|
14
|
+
warn: (msg: string) => void;
|
|
15
|
+
error: (msg: string) => void;
|
|
16
|
+
};
|
|
17
|
+
session?: {
|
|
18
|
+
id?: string;
|
|
19
|
+
cwd?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export default function orcaPlugin(context: OpenCodeContext): void;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,UAAU,eAAe;IACvB,KAAK,EAAE;QACL,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;KACrF,CAAC;IACF,KAAK,CAAC,EAAE;QACN,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC3H,CAAC;IACF,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,CAAC;IACF,OAAO,CAAC,EAAE;QACR,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAgID,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CA6FjE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { join, resolve } from 'path';
|
|
4
|
+
const SECRET_KEYS = [
|
|
5
|
+
'password', 'token', 'secret', 'api_key', 'apikey', 'api_secret',
|
|
6
|
+
'auth', 'authorization', 'bearer', 'private_key', 'access_token',
|
|
7
|
+
'refresh_token', 'credential', 'passwd', 'pwd',
|
|
8
|
+
];
|
|
9
|
+
function redactSecrets(data) {
|
|
10
|
+
if (data === null || data === undefined)
|
|
11
|
+
return data;
|
|
12
|
+
if (typeof data === 'string')
|
|
13
|
+
return data;
|
|
14
|
+
if (Array.isArray(data))
|
|
15
|
+
return data.map(redactSecrets);
|
|
16
|
+
if (typeof data !== 'object')
|
|
17
|
+
return data;
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const [key, value] of Object.entries(data)) {
|
|
20
|
+
const lowerKey = key.toLowerCase();
|
|
21
|
+
if (SECRET_KEYS.some((s) => lowerKey.includes(s))) {
|
|
22
|
+
result[key] = '[REDACTED]';
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
result[key] = redactSecrets(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function buildPayload(event, data, sessionId) {
|
|
31
|
+
return {
|
|
32
|
+
version: 1,
|
|
33
|
+
host: 'opencode',
|
|
34
|
+
event,
|
|
35
|
+
payload: redactSecrets(data),
|
|
36
|
+
session_id: sessionId,
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function findOrca(cwd) {
|
|
41
|
+
try {
|
|
42
|
+
const which = execSync('which orca', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
43
|
+
const bin = which.trim();
|
|
44
|
+
if (bin)
|
|
45
|
+
return bin;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// orca not in PATH
|
|
49
|
+
}
|
|
50
|
+
const candidates = [
|
|
51
|
+
cwd ? join(cwd, 'zig-out', 'bin', 'orca') : null,
|
|
52
|
+
cwd ? join(cwd, '..', 'zig-out', 'bin', 'orca') : null,
|
|
53
|
+
cwd ? join(cwd, '..', '..', 'zig-out', 'bin', 'orca') : null,
|
|
54
|
+
resolve('zig-out', 'bin', 'orca'),
|
|
55
|
+
resolve('..', 'zig-out', 'bin', 'orca'),
|
|
56
|
+
resolve('..', '..', 'zig-out', 'bin', 'orca'),
|
|
57
|
+
].filter((p) => p !== null);
|
|
58
|
+
for (const p of candidates) {
|
|
59
|
+
if (existsSync(p))
|
|
60
|
+
return p;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
async function callOrca(orcaBin, event, data, sessionId, blocking, shell, logger) {
|
|
65
|
+
const payload = buildPayload(event, data, sessionId);
|
|
66
|
+
const payloadJson = JSON.stringify(payload);
|
|
67
|
+
let stdout = '';
|
|
68
|
+
try {
|
|
69
|
+
if (shell?.$) {
|
|
70
|
+
const result = await shell.$ `echo ${payloadJson} | ${orcaBin} hook opencode ${event}`;
|
|
71
|
+
stdout = result.stdout ?? '';
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
stdout = execSync(`${orcaBin} hook opencode ${event}`, {
|
|
75
|
+
input: payloadJson,
|
|
76
|
+
encoding: 'utf-8',
|
|
77
|
+
timeout: blocking ? 15000 : 10000,
|
|
78
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (!stdout.trim()) {
|
|
82
|
+
return { decision: 'allow' };
|
|
83
|
+
}
|
|
84
|
+
return JSON.parse(stdout);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const safeErr = redactSecrets({ message: err.message });
|
|
88
|
+
logger?.error?.(`[orca] Hook ${event} failed: ${safeErr.message}`);
|
|
89
|
+
return blocking
|
|
90
|
+
? {
|
|
91
|
+
decision: 'block',
|
|
92
|
+
risk: 'high',
|
|
93
|
+
category: 'unknown',
|
|
94
|
+
reason: 'orca_hook_error',
|
|
95
|
+
message: 'Orca hook failed; blocking as a precaution.',
|
|
96
|
+
}
|
|
97
|
+
: {
|
|
98
|
+
decision: 'allow',
|
|
99
|
+
risk: 'unknown',
|
|
100
|
+
category: 'unknown',
|
|
101
|
+
reason: 'orca_hook_error',
|
|
102
|
+
message: 'Orca hook failed; allowing because this event is non-blocking.',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export default function orcaPlugin(context) {
|
|
107
|
+
const cwd = context.session?.cwd ?? process.cwd();
|
|
108
|
+
const sessionId = context.session?.id;
|
|
109
|
+
const orcaBin = findOrca(cwd);
|
|
110
|
+
const { shell, logger } = context;
|
|
111
|
+
if (!orcaBin) {
|
|
112
|
+
logger?.warn?.('[orca] Binary not found in PATH or typical build paths. ' +
|
|
113
|
+
'Build with: zig build (produces ./zig-out/bin/orca)');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
logger?.info?.(`[orca] Plugin loaded. Binary: ${orcaBin}`);
|
|
117
|
+
context.hooks.on('session.created', async (session) => {
|
|
118
|
+
logger?.info?.('[orca] Plugin ready for session.');
|
|
119
|
+
await callOrca(orcaBin, 'SessionStart', { session_id: session?.id }, sessionId, false, shell, logger);
|
|
120
|
+
});
|
|
121
|
+
context.hooks.on('tool.execute.before', async (toolCall) => {
|
|
122
|
+
const response = await callOrca(orcaBin, 'PreToolUse', toolCall, sessionId, true, shell, logger);
|
|
123
|
+
if (response.decision === 'block') {
|
|
124
|
+
const msg = response.message || response.reason || 'Blocked by Orca policy';
|
|
125
|
+
logger?.error?.(`[orca] Blocked tool execution: ${msg}`);
|
|
126
|
+
throw new Error(`Orca blocked tool execution: ${msg}`);
|
|
127
|
+
}
|
|
128
|
+
if (response.decision === 'warn') {
|
|
129
|
+
logger?.warn?.(`[orca] Warning: ${response.message || response.reason}`);
|
|
130
|
+
}
|
|
131
|
+
return toolCall;
|
|
132
|
+
});
|
|
133
|
+
context.hooks.on('tool.execute.after', async (result) => {
|
|
134
|
+
await callOrca(orcaBin, 'PostToolUse', result, sessionId, false, shell, logger);
|
|
135
|
+
return result;
|
|
136
|
+
});
|
|
137
|
+
context.hooks.on('permission.asked', async (permission) => {
|
|
138
|
+
const response = await callOrca(orcaBin, 'PermissionRequest', permission, sessionId, true, shell, logger);
|
|
139
|
+
if (response.decision === 'block') {
|
|
140
|
+
const msg = response.message || response.reason || 'Blocked by Orca policy';
|
|
141
|
+
logger?.error?.(`[orca] Blocked permission: ${msg}`);
|
|
142
|
+
throw new Error(`Orca blocked permission request: ${msg}`);
|
|
143
|
+
}
|
|
144
|
+
if (response.decision === 'warn') {
|
|
145
|
+
logger?.warn?.(`[orca] Permission warning: ${response.message || response.reason}`);
|
|
146
|
+
}
|
|
147
|
+
return permission;
|
|
148
|
+
});
|
|
149
|
+
context.hooks.on('file.edited', async (edit) => {
|
|
150
|
+
await callOrca(orcaBin, 'FileEdit', edit, sessionId, false, shell, logger);
|
|
151
|
+
return edit;
|
|
152
|
+
});
|
|
153
|
+
context.hooks.on('command.executed', async (command) => {
|
|
154
|
+
await callOrca(orcaBin, 'CommandExecuted', command, sessionId, false, shell, logger);
|
|
155
|
+
return command;
|
|
156
|
+
});
|
|
157
|
+
context.hooks.on('session.updated', async (session) => {
|
|
158
|
+
await callOrca(orcaBin, 'SessionUpdate', session, sessionId, false, shell, logger);
|
|
159
|
+
return session;
|
|
160
|
+
});
|
|
161
|
+
context.hooks.on('session.idle', async (session) => {
|
|
162
|
+
await callOrca(orcaBin, 'SessionIdle', session, sessionId, false, shell, logger);
|
|
163
|
+
return session;
|
|
164
|
+
});
|
|
165
|
+
context.hooks.on('session.error', async (error) => {
|
|
166
|
+
const safeError = redactSecrets({
|
|
167
|
+
message: error?.message,
|
|
168
|
+
stack: error?.stack,
|
|
169
|
+
type: error?.type,
|
|
170
|
+
});
|
|
171
|
+
await callOrca(orcaBin, 'SessionError', safeError, sessionId, false, shell, logger);
|
|
172
|
+
return error;
|
|
173
|
+
});
|
|
174
|
+
context.hooks.on('shell.env', async (env) => {
|
|
175
|
+
const safeEnv = redactSecrets(env);
|
|
176
|
+
await callOrca(orcaBin, 'ShellEnv', safeEnv, sessionId, false, shell, logger);
|
|
177
|
+
return env;
|
|
178
|
+
});
|
|
179
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "orca-opencode-plugin",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "OpenCode plugin wrapper for Orca runtime guardrails.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"package.json"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"opencode",
|
|
15
|
+
"plugin",
|
|
16
|
+
"orca",
|
|
17
|
+
"ai-agents",
|
|
18
|
+
"security",
|
|
19
|
+
"guardrails"
|
|
20
|
+
],
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18.0.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"pack:dry-run": "npm pack --dry-run"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/chriskarani/orca.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/chriskarani/orca#readme",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/chriskarani/orca/issues"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^25.6.2",
|
|
39
|
+
"typescript": "^6.0.3"
|
|
40
|
+
}
|
|
41
|
+
}
|