codiedev 0.9.49 → 0.9.51
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/codie.js +25 -1
- package/dist/codieRuntime.d.ts +11 -1
- package/dist/codieRuntime.js +20 -3
- package/dist/codieRuntimeInstall.d.ts +12 -11
- package/dist/codieRuntimeInstall.js +3 -1
- package/dist/codieStartup.d.ts +24 -0
- package/dist/codieStartup.js +29 -0
- package/dist/hook.js +5 -1
- package/dist/repoResolver.js +10 -4
- package/dist/securityPolicy.d.ts +9 -1
- package/dist/securityPolicy.js +18 -6
- package/dist/upgradeNudge.d.ts +1 -0
- package/dist/upgradeNudge.js +1 -0
- package/dist/utils.js +8 -0
- package/package.json +2 -1
package/dist/codie.js
CHANGED
|
@@ -53,6 +53,7 @@ const configDir_1 = require("./configDir");
|
|
|
53
53
|
const codieLauncher_1 = require("./codieLauncher");
|
|
54
54
|
const codieRuntime_1 = require("./codieRuntime");
|
|
55
55
|
const codieRuntimeInstall_1 = require("./codieRuntimeInstall");
|
|
56
|
+
const codieStartup_1 = require("./codieStartup");
|
|
56
57
|
const upgradeNudge_1 = require("./upgradeNudge");
|
|
57
58
|
function git(args) {
|
|
58
59
|
const result = (0, child_process_1.spawnSync)("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
@@ -300,6 +301,10 @@ async function main() {
|
|
|
300
301
|
process.exitCode = update.status ?? 0;
|
|
301
302
|
return;
|
|
302
303
|
}
|
|
304
|
+
const policyRefresh = await (0, codieStartup_1.refreshCodieSecurityPolicy)(connected);
|
|
305
|
+
if (policyRefresh.status === "cached") {
|
|
306
|
+
console.error(`codie: security policy refresh failed; using the cached policy (${policyRefresh.error})`);
|
|
307
|
+
}
|
|
303
308
|
const gatewayUrl = process.env.CODIEDEV_GATEWAY_URL || "https://gateway.codiedev.com/api/v1";
|
|
304
309
|
const catalog = await (0, codieLauncher_1.fetchApprovedCatalog)({ baseUrl: gatewayUrl, key });
|
|
305
310
|
const parsed = (0, codieLauncher_1.parseCodieArgs)(process.argv.slice(2));
|
|
@@ -310,11 +315,20 @@ async function main() {
|
|
|
310
315
|
}
|
|
311
316
|
(0, codieLauncher_1.validateCodieArgs)(parsed.args, catalog);
|
|
312
317
|
const stateDir = (0, configDir_1.codiedevStateDir)();
|
|
313
|
-
const runtime = (0, codieRuntimeInstall_1.ensureCodieRuntimeBinary)({
|
|
318
|
+
const runtime = await (0, codieRuntimeInstall_1.ensureCodieRuntimeBinary)({
|
|
314
319
|
resolve: () => (0, codieRuntime_1.resolveCodieRuntime)({
|
|
315
320
|
env: process.env,
|
|
316
321
|
stateDir,
|
|
317
322
|
existsSync: (candidate) => fs.existsSync(candidate),
|
|
323
|
+
readInstalledVersion: (candidate) => {
|
|
324
|
+
try {
|
|
325
|
+
const value = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
326
|
+
return typeof value.version === "string" ? value.version : null;
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
},
|
|
318
332
|
resolveBundled: () => {
|
|
319
333
|
try {
|
|
320
334
|
return require.resolve("opencode-ai/bin/opencode.exe");
|
|
@@ -325,6 +339,16 @@ async function main() {
|
|
|
325
339
|
},
|
|
326
340
|
}),
|
|
327
341
|
install: (missing) => (0, codieRuntimeInstall_1.installCodieRuntimeOnDisk)(missing, stateDir),
|
|
342
|
+
confirmUpdate: async (outdated) => {
|
|
343
|
+
console.error("");
|
|
344
|
+
console.error(`Codie harness ${outdated.expectedVersion} is available (you're on ${outdated.currentVersion}).`);
|
|
345
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
346
|
+
console.error("Restart `codie` in an interactive terminal to update the harness.");
|
|
347
|
+
console.error("");
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
return await (0, upgradeNudge_1.promptYesNo)(" Update the harness now? [y/N] ");
|
|
351
|
+
},
|
|
328
352
|
});
|
|
329
353
|
const metadataPlugin = (0, url_1.pathToFileURL)(assetPath("opencode-plugin.mjs")).href;
|
|
330
354
|
const capturePlugin = (0, codieLauncher_1.resolveCapturePlugin)({ homeDir: os.homedir(), existsSync: fs.existsSync });
|
package/dist/codieRuntime.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const OPENCODE_RUNTIME_SPEC = "opencode-ai@1.18.4";
|
|
2
|
+
export declare const OPENCODE_RUNTIME_VERSION: string;
|
|
2
3
|
export declare const CODIE_MIN_NODE_MAJOR = 20;
|
|
3
4
|
export type CodieRuntime = {
|
|
4
5
|
kind: "ready";
|
|
@@ -8,12 +9,21 @@ export type CodieRuntime = {
|
|
|
8
9
|
installDir: string;
|
|
9
10
|
binary: string;
|
|
10
11
|
spec: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "outdated";
|
|
14
|
+
installDir: string;
|
|
15
|
+
binary: string;
|
|
16
|
+
spec: string;
|
|
17
|
+
currentVersion: string;
|
|
18
|
+
expectedVersion: string;
|
|
11
19
|
};
|
|
12
20
|
export declare function codieRuntimeDir(stateDir: string): string;
|
|
13
|
-
export declare function
|
|
21
|
+
export declare function installedRuntimePackageJson(stateDir: string): string;
|
|
22
|
+
export declare function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion, resolveBundled, }: {
|
|
14
23
|
env: Record<string, string | undefined>;
|
|
15
24
|
stateDir: string;
|
|
16
25
|
existsSync: (candidate: string) => boolean;
|
|
26
|
+
readInstalledVersion?: (packageJson: string) => string | null;
|
|
17
27
|
resolveBundled: () => string | null;
|
|
18
28
|
}): CodieRuntime;
|
|
19
29
|
export declare function assertCodieNodeVersion(version: string): void;
|
package/dist/codieRuntime.js
CHANGED
|
@@ -43,8 +43,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
43
43
|
};
|
|
44
44
|
})();
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.CODIE_MIN_NODE_MAJOR = exports.OPENCODE_RUNTIME_SPEC = void 0;
|
|
46
|
+
exports.CODIE_MIN_NODE_MAJOR = exports.OPENCODE_RUNTIME_VERSION = exports.OPENCODE_RUNTIME_SPEC = void 0;
|
|
47
47
|
exports.codieRuntimeDir = codieRuntimeDir;
|
|
48
|
+
exports.installedRuntimePackageJson = installedRuntimePackageJson;
|
|
48
49
|
exports.resolveCodieRuntime = resolveCodieRuntime;
|
|
49
50
|
exports.assertCodieNodeVersion = assertCodieNodeVersion;
|
|
50
51
|
const path = __importStar(require("path"));
|
|
@@ -52,6 +53,7 @@ const path = __importStar(require("path"));
|
|
|
52
53
|
// recognizes byte-for-byte, so a floating version would silently regress the
|
|
53
54
|
// terminal branding whenever OpenCode ships a new build.
|
|
54
55
|
exports.OPENCODE_RUNTIME_SPEC = "opencode-ai@1.18.4";
|
|
56
|
+
exports.OPENCODE_RUNTIME_VERSION = exports.OPENCODE_RUNTIME_SPEC.slice(exports.OPENCODE_RUNTIME_SPEC.lastIndexOf("@") + 1);
|
|
55
57
|
// The harness needs 20; capture does not. package.json `engines` stays >=18 so
|
|
56
58
|
// `codiedev connect` still installs for Node 18 users — this floor is enforced
|
|
57
59
|
// at `codie` launch instead.
|
|
@@ -62,7 +64,10 @@ function codieRuntimeDir(stateDir) {
|
|
|
62
64
|
function installedBinary(stateDir) {
|
|
63
65
|
return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai", "bin", "opencode.exe");
|
|
64
66
|
}
|
|
65
|
-
function
|
|
67
|
+
function installedRuntimePackageJson(stateDir) {
|
|
68
|
+
return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai", "package.json");
|
|
69
|
+
}
|
|
70
|
+
function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion, resolveBundled, }) {
|
|
66
71
|
// 1. Explicit override — the air-gapped / pre-provisioned escape hatch.
|
|
67
72
|
const override = env.CODIEDEV_OPENCODE_BINARY?.trim();
|
|
68
73
|
if (override) {
|
|
@@ -78,8 +83,20 @@ function resolveCodieRuntime({ env, stateDir, existsSync, resolveBundled, }) {
|
|
|
78
83
|
return { kind: "ready", binary: bundled };
|
|
79
84
|
// 3. The lazily installed engine.
|
|
80
85
|
const binary = installedBinary(stateDir);
|
|
81
|
-
if (existsSync(binary))
|
|
86
|
+
if (existsSync(binary)) {
|
|
87
|
+
const currentVersion = readInstalledVersion?.(installedRuntimePackageJson(stateDir)) ?? null;
|
|
88
|
+
if (currentVersion && currentVersion !== exports.OPENCODE_RUNTIME_VERSION) {
|
|
89
|
+
return {
|
|
90
|
+
kind: "outdated",
|
|
91
|
+
installDir: codieRuntimeDir(stateDir),
|
|
92
|
+
binary,
|
|
93
|
+
spec: exports.OPENCODE_RUNTIME_SPEC,
|
|
94
|
+
currentVersion,
|
|
95
|
+
expectedVersion: exports.OPENCODE_RUNTIME_VERSION,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
82
98
|
return { kind: "ready", binary };
|
|
99
|
+
}
|
|
83
100
|
return { kind: "missing", installDir: codieRuntimeDir(stateDir), binary, spec: exports.OPENCODE_RUNTIME_SPEC };
|
|
84
101
|
}
|
|
85
102
|
function assertCodieNodeVersion(version) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { CodieRuntime } from "./codieRuntime";
|
|
2
|
+
type InstallableCodieRuntime = Exclude<CodieRuntime, {
|
|
3
|
+
kind: "ready";
|
|
4
|
+
}>;
|
|
2
5
|
export declare function buildRuntimeInstallArgs(stagingDir: string, spec: string): string[];
|
|
3
6
|
export interface InstallDeps {
|
|
4
|
-
runtime:
|
|
5
|
-
kind: "missing";
|
|
6
|
-
}>;
|
|
7
|
+
runtime: InstallableCodieRuntime;
|
|
7
8
|
makeStagingDir: () => string;
|
|
8
9
|
run: (args: string[]) => {
|
|
9
10
|
status: number | null;
|
|
@@ -15,13 +16,13 @@ export interface InstallDeps {
|
|
|
15
16
|
log: (message: string) => void;
|
|
16
17
|
}
|
|
17
18
|
export declare function installCodieRuntime(deps: InstallDeps): void;
|
|
18
|
-
export declare function ensureCodieRuntimeBinary({ resolve, install, }: {
|
|
19
|
+
export declare function ensureCodieRuntimeBinary({ resolve, install, confirmUpdate, }: {
|
|
19
20
|
resolve: () => CodieRuntime;
|
|
20
|
-
install: (runtime:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}>, stateDir: string): void;
|
|
21
|
+
install: (runtime: InstallableCodieRuntime) => void;
|
|
22
|
+
confirmUpdate?: (runtime: Extract<CodieRuntime, {
|
|
23
|
+
kind: "outdated";
|
|
24
|
+
}>) => Promise<boolean>;
|
|
25
|
+
}): Promise<string>;
|
|
26
|
+
export declare function installCodieRuntimeOnDisk(runtime: InstallableCodieRuntime, stateDir: string): void;
|
|
27
27
|
export declare function defaultStagingRoot(): string;
|
|
28
|
+
export {};
|
|
@@ -98,10 +98,12 @@ function installCodieRuntime(deps) {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
// Resolve the engine, downloading it once if this is the first `codie` run.
|
|
101
|
-
function ensureCodieRuntimeBinary({ resolve, install, }) {
|
|
101
|
+
async function ensureCodieRuntimeBinary({ resolve, install, confirmUpdate = async () => false, }) {
|
|
102
102
|
const runtime = resolve();
|
|
103
103
|
if (runtime.kind === "ready")
|
|
104
104
|
return runtime.binary;
|
|
105
|
+
if (runtime.kind === "outdated" && !(await confirmUpdate(runtime)))
|
|
106
|
+
return runtime.binary;
|
|
105
107
|
install(runtime);
|
|
106
108
|
return runtime.binary;
|
|
107
109
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AgentSurface, EndpointSecurityPolicy } from "./security";
|
|
2
|
+
import type { AgentSecurityEntitlement } from "./securityFeature";
|
|
3
|
+
export interface CodieStartupConfig extends AgentSecurityEntitlement {
|
|
4
|
+
backendUrl?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
companyId?: string;
|
|
7
|
+
}
|
|
8
|
+
export type CodiePolicyRefreshResult = {
|
|
9
|
+
status: "disabled";
|
|
10
|
+
} | {
|
|
11
|
+
status: "synced";
|
|
12
|
+
policy: EndpointSecurityPolicy;
|
|
13
|
+
} | {
|
|
14
|
+
status: "cached";
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
/** Refresh the endpoint policy before Codie hands the terminal to OpenCode.
|
|
18
|
+
* Enforcement remains available offline because hooks keep using the last
|
|
19
|
+
* verified company-scoped policy when this best-effort refresh cannot land. */
|
|
20
|
+
export declare function refreshCodieSecurityPolicy(config: CodieStartupConfig, syncPolicy?: (config: {
|
|
21
|
+
backendUrl: string;
|
|
22
|
+
token: string;
|
|
23
|
+
companyId: string;
|
|
24
|
+
}, source?: AgentSurface) => Promise<EndpointSecurityPolicy>): Promise<CodiePolicyRefreshResult>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refreshCodieSecurityPolicy = refreshCodieSecurityPolicy;
|
|
4
|
+
const securityFeature_1 = require("./securityFeature");
|
|
5
|
+
const securityPolicy_1 = require("./securityPolicy");
|
|
6
|
+
/** Refresh the endpoint policy before Codie hands the terminal to OpenCode.
|
|
7
|
+
* Enforcement remains available offline because hooks keep using the last
|
|
8
|
+
* verified company-scoped policy when this best-effort refresh cannot land. */
|
|
9
|
+
async function refreshCodieSecurityPolicy(config, syncPolicy = securityPolicy_1.syncEndpointSecurityPolicy) {
|
|
10
|
+
if (!(0, securityFeature_1.isAgentSecurityEnabled)(config))
|
|
11
|
+
return { status: "disabled" };
|
|
12
|
+
if (!config.backendUrl || !config.token || !config.companyId) {
|
|
13
|
+
return { status: "cached", error: "connected account details are incomplete" };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const policy = await syncPolicy({
|
|
17
|
+
backendUrl: config.backendUrl,
|
|
18
|
+
token: config.token,
|
|
19
|
+
companyId: config.companyId,
|
|
20
|
+
}, "codie-harness");
|
|
21
|
+
return { status: "synced", policy };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
status: "cached",
|
|
26
|
+
error: error instanceof Error ? error.message : String(error),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/hook.js
CHANGED
|
@@ -366,7 +366,11 @@ async function runSecurityEventUpload() {
|
|
|
366
366
|
endpointName: config.deviceName,
|
|
367
367
|
cliVersion: version_1.CLI_VERSION,
|
|
368
368
|
});
|
|
369
|
-
const result = await postJsonForResponse(`${config.backendUrl}/api/cli/securityEvent`, { ...eventWithEndpoint }, config.token,
|
|
369
|
+
const result = await postJsonForResponse(`${config.backendUrl}/api/cli/securityEvent`, { ...eventWithEndpoint }, config.token,
|
|
370
|
+
// Leave room for a cold backend and durable scheduling. This uploader is
|
|
371
|
+
// detached, so the network budget never delays the developer's prompt or
|
|
372
|
+
// tool call. Policy refreshes use the separately signed sync endpoint.
|
|
373
|
+
5_000);
|
|
370
374
|
if (result?.policy?.schemaVersion === 1) {
|
|
371
375
|
(0, securityPolicy_1.writeEndpointSecurityPolicy)(result.policy, undefined, undefined, config.companyId);
|
|
372
376
|
}
|
package/dist/repoResolver.js
CHANGED
|
@@ -13,14 +13,20 @@ function parseRemoteUrl(url) {
|
|
|
13
13
|
let s = url.trim();
|
|
14
14
|
if (s.endsWith(".git"))
|
|
15
15
|
s = s.slice(0, -4);
|
|
16
|
-
const ssh = s.match(/^git@([^:]+):(.+)$/);
|
|
17
|
-
if (ssh) {
|
|
18
|
-
return { host: ssh[1].toLowerCase(), ownerName: ssh[2].toLowerCase() };
|
|
19
|
-
}
|
|
20
16
|
const https = s.match(/^https?:\/\/([^/]+)\/(.+)$/);
|
|
21
17
|
if (https) {
|
|
22
18
|
return { host: https[1].toLowerCase(), ownerName: https[2].toLowerCase() };
|
|
23
19
|
}
|
|
20
|
+
// Codie strips SSH userinfo before putting a remote in the gateway header,
|
|
21
|
+
// so `git@gitlab.com:owner/repo.git` arrives here as
|
|
22
|
+
// `gitlab.com:owner/repo.git`. Accept both forms; otherwise every SSH-cloned
|
|
23
|
+
// Harness checkout loses its repoId even though transcript capture can
|
|
24
|
+
// resolve the same raw remote correctly. Check this after URL forms so the
|
|
25
|
+
// colon in `https://` is never mistaken for an SCP separator.
|
|
26
|
+
const scp = s.match(/^(?:[^@\s]+@)?([^:/\s]+):(.+)$/);
|
|
27
|
+
if (scp) {
|
|
28
|
+
return { host: scp[1].toLowerCase(), ownerName: scp[2].toLowerCase() };
|
|
29
|
+
}
|
|
24
30
|
return null;
|
|
25
31
|
}
|
|
26
32
|
function resolveRepoForCapture(input) {
|
package/dist/securityPolicy.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { AgentSurface, EndpointSecurityPolicy } from "./security";
|
|
2
2
|
export type TrustedPolicyKeys = Record<string, string>;
|
|
3
|
+
/**
|
|
4
|
+
* Vendor policy roots are compiled into the endpoint binary. This prevents a
|
|
5
|
+
* compromised control-plane response from introducing the key that verifies
|
|
6
|
+
* that same response. Additional customer-managed roots may still be supplied
|
|
7
|
+
* through CODIEDEV_SECURITY_POLICY_PUBLIC_KEYS, but they cannot replace the
|
|
8
|
+
* Codiedev production root with the same key id.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BUILT_IN_POLICY_KEYS: TrustedPolicyKeys;
|
|
3
11
|
export declare function trustedPolicyKeysFromEnvironment(env?: NodeJS.ProcessEnv): TrustedPolicyKeys;
|
|
4
12
|
export declare function verifyEndpointSecurityPolicySignature(policy: EndpointSecurityPolicy, trustedKeys?: TrustedPolicyKeys): {
|
|
5
13
|
ok: boolean;
|
|
@@ -21,4 +29,4 @@ export declare function syncEndpointSecurityPolicy(config: {
|
|
|
21
29
|
backendUrl: string;
|
|
22
30
|
token: string;
|
|
23
31
|
companyId: string;
|
|
24
|
-
}, source?: AgentSurface, timeoutMs?: number): Promise<EndpointSecurityPolicy>;
|
|
32
|
+
}, source?: AgentSurface, timeoutMs?: number, stateDir?: string, trustedKeys?: TrustedPolicyKeys): Promise<EndpointSecurityPolicy>;
|
package/dist/securityPolicy.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.BUILT_IN_POLICY_KEYS = void 0;
|
|
36
37
|
exports.trustedPolicyKeysFromEnvironment = trustedPolicyKeysFromEnvironment;
|
|
37
38
|
exports.verifyEndpointSecurityPolicySignature = verifyEndpointSecurityPolicySignature;
|
|
38
39
|
exports.readEndpointSecurityPolicy = readEndpointSecurityPolicy;
|
|
@@ -52,6 +53,16 @@ function policyFile(companyId) {
|
|
|
52
53
|
const scope = companyId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 128);
|
|
53
54
|
return `security-policy.${scope}.json`;
|
|
54
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Vendor policy roots are compiled into the endpoint binary. This prevents a
|
|
58
|
+
* compromised control-plane response from introducing the key that verifies
|
|
59
|
+
* that same response. Additional customer-managed roots may still be supplied
|
|
60
|
+
* through CODIEDEV_SECURITY_POLICY_PUBLIC_KEYS, but they cannot replace the
|
|
61
|
+
* Codiedev production root with the same key id.
|
|
62
|
+
*/
|
|
63
|
+
exports.BUILT_IN_POLICY_KEYS = {
|
|
64
|
+
"codiedev-prod-2026-01": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA0H+UISjTn4zhd6Pk9YmrMBqnJEJmv9fXoavXorlV2cU=\n-----END PUBLIC KEY-----\n",
|
|
65
|
+
};
|
|
55
66
|
function stableJson(value) {
|
|
56
67
|
if (Array.isArray(value))
|
|
57
68
|
return `[${value.map(stableJson).join(",")}]`;
|
|
@@ -66,16 +77,17 @@ function stableJson(value) {
|
|
|
66
77
|
function trustedPolicyKeysFromEnvironment(env = process.env) {
|
|
67
78
|
const raw = env.CODIEDEV_SECURITY_POLICY_PUBLIC_KEYS;
|
|
68
79
|
if (!raw)
|
|
69
|
-
return {};
|
|
80
|
+
return { ...exports.BUILT_IN_POLICY_KEYS };
|
|
70
81
|
try {
|
|
71
82
|
const parsed = JSON.parse(raw);
|
|
72
83
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
73
|
-
return {};
|
|
74
|
-
|
|
84
|
+
return { ...exports.BUILT_IN_POLICY_KEYS };
|
|
85
|
+
const configured = Object.fromEntries(Object.entries(parsed)
|
|
75
86
|
.filter((entry) => typeof entry[1] === "string"));
|
|
87
|
+
return { ...configured, ...exports.BUILT_IN_POLICY_KEYS };
|
|
76
88
|
}
|
|
77
89
|
catch {
|
|
78
|
-
return {};
|
|
90
|
+
return { ...exports.BUILT_IN_POLICY_KEYS };
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
function verifyEndpointSecurityPolicySignature(policy, trustedKeys = trustedPolicyKeysFromEnvironment()) {
|
|
@@ -134,7 +146,7 @@ function writeEndpointSecurityPolicy(policy, stateDir = (0, configDir_1.codiedev
|
|
|
134
146
|
fs.chmodSync(temporary, 0o600);
|
|
135
147
|
fs.renameSync(temporary, target);
|
|
136
148
|
}
|
|
137
|
-
async function syncEndpointSecurityPolicy(config, source, timeoutMs = 3_000) {
|
|
149
|
+
async function syncEndpointSecurityPolicy(config, source, timeoutMs = 3_000, stateDir = (0, configDir_1.codiedevStateDir)(), trustedKeys = trustedPolicyKeysFromEnvironment()) {
|
|
138
150
|
const url = new URL("/api/cli/securityPolicy", config.backendUrl);
|
|
139
151
|
if (source)
|
|
140
152
|
url.searchParams.set("source", source);
|
|
@@ -162,6 +174,6 @@ async function syncEndpointSecurityPolicy(config, source, timeoutMs = 3_000) {
|
|
|
162
174
|
request.on("error", reject);
|
|
163
175
|
request.end();
|
|
164
176
|
});
|
|
165
|
-
writeEndpointSecurityPolicy(policy,
|
|
177
|
+
writeEndpointSecurityPolicy(policy, stateDir, trustedKeys, config.companyId);
|
|
166
178
|
return policy;
|
|
167
179
|
}
|
package/dist/upgradeNudge.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface OfferOpts {
|
|
|
13
13
|
log?: (line: string) => void;
|
|
14
14
|
isTty?: boolean;
|
|
15
15
|
}
|
|
16
|
+
export declare function promptYesNo(question: string): Promise<boolean>;
|
|
16
17
|
/**
|
|
17
18
|
* Prompt-capable sibling of maybePrintUpgradeNudge. Call this before handing
|
|
18
19
|
* the terminal to a TUI. A successful upgrade relaunches the fresh CLI and
|
package/dist/upgradeNudge.js
CHANGED
|
@@ -43,6 +43,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
43
43
|
})();
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.maybePrintUpgradeNudge = maybePrintUpgradeNudge;
|
|
46
|
+
exports.promptYesNo = promptYesNo;
|
|
46
47
|
exports.maybeOfferUpgrade = maybeOfferUpgrade;
|
|
47
48
|
const fs = __importStar(require("fs"));
|
|
48
49
|
const path = __importStar(require("path"));
|
package/dist/utils.js
CHANGED
|
@@ -2787,6 +2787,14 @@ async function runCaptureUpload(jobFile, deps) {
|
|
|
2787
2787
|
const { storageId } = await deps.uploadBytes(uploadUrl, Buffer.from(transcript, "base64"), "application/json");
|
|
2788
2788
|
body = { ...body, transcriptStorageId: storageId };
|
|
2789
2789
|
delete body.transcript;
|
|
2790
|
+
// Persist the storage id before the metadata POST. Previously a failed
|
|
2791
|
+
// captureSession request retried the entire direct upload, creating one
|
|
2792
|
+
// unreferenced raw transcript blob per attempt. Once the PUT succeeds,
|
|
2793
|
+
// every retry must reuse that exact blob.
|
|
2794
|
+
job.body = body;
|
|
2795
|
+
if (deps.writeFileSync) {
|
|
2796
|
+
deps.writeFileSync(jobFile, JSON.stringify(job), { mode: 0o600 });
|
|
2797
|
+
}
|
|
2790
2798
|
}
|
|
2791
2799
|
await deps.post(job.url, body, job.token);
|
|
2792
2800
|
// success — drop a "last session captured" breadcrumb (before removing the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codiedev",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.51",
|
|
4
4
|
"description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codiedev": "dist/cli.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"test": "vitest run",
|
|
15
15
|
"test:security-beta": "vitest run src/__tests__/security.test.ts src/__tests__/securityCommandEntitlement.test.ts src/__tests__/securityDeepScan.test.ts src/__tests__/securityDoctor.test.ts src/__tests__/securityEntitlementInstall.test.ts src/__tests__/securityFeature.test.ts src/__tests__/securityInstall.test.ts src/__tests__/securityInventory.test.ts src/__tests__/securityPilot.test.ts src/__tests__/securityPolicy.test.ts src/__tests__/securitySession.test.ts src/__tests__/codexHookTrust.test.ts src/__tests__/codieSecurityAdapterWiring.test.ts && tsc && node dist/cli.js security pilot --json",
|
|
16
16
|
"test:security-pilot": "vitest run src/__tests__/security.test.ts src/__tests__/securityInstall.test.ts src/__tests__/securityPilot.test.ts src/__tests__/codieSecurityAdapterWiring.test.ts && tsc && node dist/cli.js security pilot --json",
|
|
17
|
+
"test:opencode-attribution": "vitest run src/__tests__/repoResolver.test.ts src/__tests__/openCodeCapture.test.ts src/__tests__/openCodePluginGitRefs.test.ts src/__tests__/capturePayloadFinal.test.ts src/__tests__/captureDirectUpload.test.ts src/__tests__/resolveCaptureFinal.test.ts && tsc",
|
|
17
18
|
"test:watch": "vitest"
|
|
18
19
|
},
|
|
19
20
|
"files": [
|