@cyanautomation/kaseki-agent 1.27.5 → 1.28.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 +20 -0
- package/dist/__test-utils/openapi-assertions.d.ts +39 -0
- package/dist/__test-utils/openapi-assertions.d.ts.map +1 -0
- package/dist/__test-utils/openapi-assertions.js +101 -0
- package/dist/__test-utils/openapi-assertions.js.map +1 -0
- package/dist/cli/commands/InitCommand.d.ts.map +1 -1
- package/dist/cli/commands/InitCommand.js +3 -0
- package/dist/cli/commands/InitCommand.js.map +1 -1
- package/dist/config/ConfigManager.d.ts +12 -12
- package/dist/kaseki-api-routes.d.ts.map +1 -1
- package/dist/kaseki-api-routes.js +93 -15
- package/dist/kaseki-api-routes.js.map +1 -1
- package/dist/kaseki-api-types.d.ts +35 -5
- package/dist/kaseki-api-types.d.ts.map +1 -1
- package/dist/kaseki-api-types.js +29 -1
- package/dist/kaseki-api-types.js.map +1 -1
- package/dist/secrets/host-secrets-reader.d.ts +1 -1
- package/dist/secrets/host-secrets-reader.d.ts.map +1 -1
- package/dist/secrets/host-secrets-reader.js +6 -4
- package/dist/secrets/host-secrets-reader.js.map +1 -1
- package/dist/setup/SetupWizard.d.ts +18 -1
- package/dist/setup/SetupWizard.d.ts.map +1 -1
- package/dist/setup/SetupWizard.js +128 -6
- package/dist/setup/SetupWizard.js.map +1 -1
- package/package.json +1 -1
- package/scripts/docker-entrypoint.sh +4 -4
- package/scripts/kaseki-preflight-docker-compose.sh +296 -0
- package/scripts/kaseki-setup-host.sh +49 -6
- package/scripts/startup-checks.sh +2 -2
- package/dist/setup/env-defaults.d.ts +0 -86
- package/dist/setup/env-defaults.d.ts.map +0 -1
- package/dist/setup/env-defaults.js +0 -403
- package/dist/setup/env-defaults.js.map +0 -1
package/README.md
CHANGED
|
@@ -29,6 +29,26 @@ KASEKI_API_KEY=sk-dev kaseki-agent list
|
|
|
29
29
|
KASEKI_API_KEY=sk-dev kaseki-agent report kaseki-1
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
### First-Run API Host Setup
|
|
33
|
+
|
|
34
|
+
For a Docker Compose API host, prepare storage and secrets before starting the
|
|
35
|
+
service:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cd /agents/kaseki-agent
|
|
39
|
+
sudo ./scripts/kaseki-setup-host.sh --fix
|
|
40
|
+
docker compose up -d --force-recreate
|
|
41
|
+
|
|
42
|
+
curl -H "Authorization: Bearer $(cat ~/secrets/kaseki_api_keys)" \
|
|
43
|
+
http://localhost:8080/api/preflight
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The host prep helper creates `/agents`, `/agents/kaseki-results`,
|
|
47
|
+
`/agents/kaseki-runs`, and `/agents/kaseki-cache` for UID/GID `10000:10000`,
|
|
48
|
+
then normalizes `~/secrets` to directory mode `0750` and file mode `0640` with
|
|
49
|
+
group `10000`. If preflight reports a deleted bind mount, recreate the container
|
|
50
|
+
after rerunning the helper.
|
|
51
|
+
|
|
32
52
|
### Without Global Install
|
|
33
53
|
|
|
34
54
|
```bash
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared OpenAPI test assertion helpers
|
|
3
|
+
* Reduces complexity of openapi-spec-generator.test.ts by extracting common patterns
|
|
4
|
+
* @jest-environment node
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Iterate through all paths and methods in an OpenAPI spec, executing a callback for each
|
|
8
|
+
* Replaces nested Object.entries().forEach() patterns with a single helper call
|
|
9
|
+
*/
|
|
10
|
+
export declare function forEachPathOperation(paths: Record<string, Record<string, unknown>>, callback: (pathName: string, method: string, operation: Record<string, unknown>) => void): void;
|
|
11
|
+
/**
|
|
12
|
+
* Assert that a specific endpoint has a given HTTP status code documented in responses
|
|
13
|
+
*/
|
|
14
|
+
export declare function assertStatusCode(spec: Record<string, unknown>, endpoint: string, method: string, statusCode: string | number): void;
|
|
15
|
+
/**
|
|
16
|
+
* Assert that a schema property has the expected constraints and types
|
|
17
|
+
*/
|
|
18
|
+
export declare function assertSchemaProperty(schema: Record<string, Record<string, unknown>>, propertyName: string, expectedType?: string, expectedFormat?: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Assert that an endpoint requires or doesn't require authentication
|
|
21
|
+
*/
|
|
22
|
+
export declare function assertAuthRequired(spec: Record<string, unknown>, endpoint: string, shouldBeProtected: boolean): void;
|
|
23
|
+
/**
|
|
24
|
+
* Assert that all operations in a path item have required fields
|
|
25
|
+
*/
|
|
26
|
+
export declare function assertPathItemOperationsComplete(pathItem: Record<string, Record<string, unknown>>, requiredFields: string[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Assert that a schema is properly structured with type and properties
|
|
29
|
+
*/
|
|
30
|
+
export declare function assertSchemaStructure(schema: Record<string, unknown>, expectedType?: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Assert that a field is in the required array of a schema
|
|
33
|
+
*/
|
|
34
|
+
export declare function assertFieldRequired(schema: Record<string, unknown>, fieldName: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Assert that all paths have at least one operation defined (GET, POST, etc.)
|
|
37
|
+
*/
|
|
38
|
+
export declare function assertAllPathsHaveOperations(paths: Record<string, Record<string, unknown>>): void;
|
|
39
|
+
//# sourceMappingURL=openapi-assertions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-assertions.d.ts","sourceRoot":"","sources":["../../src/__test-utils/openapi-assertions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC9C,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GACvF,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAAG,MAAM,GAC1B,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC/C,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,IAAI,CAWN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,OAAO,GACzB,IAAI,CAoBN;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACjD,cAAc,EAAE,MAAM,EAAE,GACvB,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,YAAY,SAAW,GACtB,IAAI,CAIN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,IAAI,CAKN;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAOjG"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared OpenAPI test assertion helpers
|
|
3
|
+
* Reduces complexity of openapi-spec-generator.test.ts by extracting common patterns
|
|
4
|
+
* @jest-environment node
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Iterate through all paths and methods in an OpenAPI spec, executing a callback for each
|
|
8
|
+
* Replaces nested Object.entries().forEach() patterns with a single helper call
|
|
9
|
+
*/
|
|
10
|
+
export function forEachPathOperation(paths, callback) {
|
|
11
|
+
Object.entries(paths).forEach(([pathName, pathItem]) => {
|
|
12
|
+
Object.entries(pathItem).forEach(([method, operation]) => {
|
|
13
|
+
callback(pathName, method, operation);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Assert that a specific endpoint has a given HTTP status code documented in responses
|
|
19
|
+
*/
|
|
20
|
+
export function assertStatusCode(spec, endpoint, method, statusCode) {
|
|
21
|
+
const paths = spec.paths;
|
|
22
|
+
const pathItem = paths?.[endpoint];
|
|
23
|
+
const operation = pathItem?.[method.toLowerCase()];
|
|
24
|
+
const responses = operation?.responses;
|
|
25
|
+
expect(responses).toBeDefined();
|
|
26
|
+
expect(responses?.[statusCode.toString()]).toBeDefined();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Assert that a schema property has the expected constraints and types
|
|
30
|
+
*/
|
|
31
|
+
export function assertSchemaProperty(schema, propertyName, expectedType, expectedFormat) {
|
|
32
|
+
const properties = schema.properties;
|
|
33
|
+
const property = properties?.[propertyName];
|
|
34
|
+
expect(property).toBeDefined();
|
|
35
|
+
if (expectedType) {
|
|
36
|
+
expect(property?.type).toBe(expectedType);
|
|
37
|
+
}
|
|
38
|
+
if (expectedFormat) {
|
|
39
|
+
expect(property?.format).toBe(expectedFormat);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Assert that an endpoint requires or doesn't require authentication
|
|
44
|
+
*/
|
|
45
|
+
export function assertAuthRequired(spec, endpoint, shouldBeProtected) {
|
|
46
|
+
const paths = spec.paths;
|
|
47
|
+
const pathItem = paths?.[endpoint];
|
|
48
|
+
expect(pathItem).toBeDefined();
|
|
49
|
+
Object.entries(pathItem).forEach(([, operation]) => {
|
|
50
|
+
const op = operation;
|
|
51
|
+
const security = op.security;
|
|
52
|
+
if (shouldBeProtected) {
|
|
53
|
+
expect(security).toBeDefined();
|
|
54
|
+
expect(Array.isArray(security)).toBe(true);
|
|
55
|
+
expect(security?.length).toBeGreaterThan(0);
|
|
56
|
+
expect(security?.[0]?.BearerAuth).toBeDefined();
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Public endpoint: security should be empty array or undefined
|
|
60
|
+
expect(security === undefined || (Array.isArray(security) && security.length === 0)).toBe(true);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Assert that all operations in a path item have required fields
|
|
66
|
+
*/
|
|
67
|
+
export function assertPathItemOperationsComplete(pathItem, requiredFields) {
|
|
68
|
+
Object.entries(pathItem).forEach(([, operation]) => {
|
|
69
|
+
requiredFields.forEach((field) => {
|
|
70
|
+
expect(operation[field]).toBeDefined();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Assert that a schema is properly structured with type and properties
|
|
76
|
+
*/
|
|
77
|
+
export function assertSchemaStructure(schema, expectedType = 'object') {
|
|
78
|
+
expect(schema.type).toBe(expectedType);
|
|
79
|
+
expect(schema.properties).toBeDefined();
|
|
80
|
+
expect(typeof schema.properties).toBe('object');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Assert that a field is in the required array of a schema
|
|
84
|
+
*/
|
|
85
|
+
export function assertFieldRequired(schema, fieldName) {
|
|
86
|
+
const required = schema.required;
|
|
87
|
+
expect(required).toBeDefined();
|
|
88
|
+
expect(Array.isArray(required)).toBe(true);
|
|
89
|
+
expect(required).toContain(fieldName);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Assert that all paths have at least one operation defined (GET, POST, etc.)
|
|
93
|
+
*/
|
|
94
|
+
export function assertAllPathsHaveOperations(paths) {
|
|
95
|
+
const httpMethods = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'];
|
|
96
|
+
Object.entries(paths).forEach(([, pathItem]) => {
|
|
97
|
+
const hasOperation = httpMethods.some((method) => method in pathItem);
|
|
98
|
+
expect(hasOperation).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=openapi-assertions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-assertions.js","sourceRoot":"","sources":["../../src/__test-utils/openapi-assertions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InitCommand.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/InitCommand.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAK7C,qBAAa,WAAY,SAAQ,WAAW;IACpC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"InitCommand.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/InitCommand.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAK7C,qBAAa,WAAY,SAAQ,WAAW;IACpC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAoC9C;;OAEG;IACH,OAAO,CAAC,SAAS;IA4CjB;;OAEG;IACH,OAAO,CAAC,cAAc;CA4DvB"}
|
|
@@ -17,6 +17,7 @@ export class InitCommand extends BaseCommand {
|
|
|
17
17
|
// Check for command-specific flags
|
|
18
18
|
const dryRun = args.includes('--dry-run');
|
|
19
19
|
const importLegacy = args.includes('--import-legacy');
|
|
20
|
+
const force = args.includes('--force');
|
|
20
21
|
// Show help if requested
|
|
21
22
|
if (args.includes('--help') || args.includes('-h')) {
|
|
22
23
|
this.printHelp();
|
|
@@ -27,6 +28,7 @@ export class InitCommand extends BaseCommand {
|
|
|
27
28
|
const context = await wizard.run({
|
|
28
29
|
dryRun,
|
|
29
30
|
importLegacy,
|
|
31
|
+
force,
|
|
30
32
|
});
|
|
31
33
|
// Show path-specific guidance
|
|
32
34
|
if (!dryRun) {
|
|
@@ -55,6 +57,7 @@ USAGE
|
|
|
55
57
|
OPTIONS
|
|
56
58
|
--dry-run Validate setup without saving configuration
|
|
57
59
|
--import-legacy Migrate configuration from old setup paths
|
|
60
|
+
--force Skip permission validation and proceed (advanced users only)
|
|
58
61
|
--help, -h Show this help message
|
|
59
62
|
|
|
60
63
|
DESCRIPTION
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InitCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/InitCommand.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAExC,MAAM,OAAO,WAAY,SAAQ,WAAW;IAC1C,KAAK,CAAC,OAAO,CAAC,IAAc;QAC1B,IAAI,CAAC;YACH,mCAAmC;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"InitCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/InitCommand.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAExC,MAAM,OAAO,WAAY,SAAQ,WAAW;IAC1C,KAAK,CAAC,OAAO,CAAC,IAAc;QAC1B,IAAI,CAAC;YACH,mCAAmC;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YACtD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAEvC,yBAAyB;YACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjB,OAAO,CAAC,CAAC;YACX,CAAC;YAED,+BAA+B;YAC/B,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC;gBAC/B,MAAM;gBACN,YAAY;gBACZ,KAAK;aACN,CAAC,CAAC;YAEH,8BAA8B;YAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YAED,OAAO,CAAC,CAAC;QACX,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC;YACvC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG,EAAE,CAAC;gBAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IAED;;OAEG;IACK,SAAS;QACf,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCX,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,OAAY;QACjC,MAAM,UAAU,GAA2B;YACzC,YAAY,EAAE;;;;;;;;;;;OAWb;YAED,WAAW,EAAE;;;;;;;;;;;;;;;OAeZ;YAED,gBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;OAsBjB;SACF,CAAC;QAEF,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -35,14 +35,14 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
35
35
|
timeout_seconds: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
|
|
36
36
|
guardrails: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
37
37
|
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
timeout_seconds?: number | undefined;
|
|
38
39
|
model?: string | undefined;
|
|
39
40
|
provider?: string | undefined;
|
|
40
|
-
timeout_seconds?: number | undefined;
|
|
41
41
|
guardrails?: boolean | undefined;
|
|
42
42
|
}, {
|
|
43
|
+
timeout_seconds?: number | undefined;
|
|
43
44
|
model?: string | undefined;
|
|
44
45
|
provider?: string | undefined;
|
|
45
|
-
timeout_seconds?: number | undefined;
|
|
46
46
|
guardrails?: boolean | undefined;
|
|
47
47
|
}>>;
|
|
48
48
|
repo: z.ZodOptional<z.ZodObject<{
|
|
@@ -71,22 +71,22 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
71
71
|
}, "strip", z.ZodTypeAny, {
|
|
72
72
|
allowlist?: string[] | undefined;
|
|
73
73
|
commands?: string[] | undefined;
|
|
74
|
+
max_diff_bytes?: number | undefined;
|
|
74
75
|
skip_missing_npm_scripts?: boolean | undefined;
|
|
75
76
|
fail_fast?: boolean | undefined;
|
|
76
77
|
validate_after_agent_failure?: boolean | undefined;
|
|
77
78
|
validation_allowlist?: string[] | undefined;
|
|
78
79
|
restore_disallowed_changes?: boolean | undefined;
|
|
79
|
-
max_diff_bytes?: number | undefined;
|
|
80
80
|
allow_empty_diff?: boolean | undefined;
|
|
81
81
|
}, {
|
|
82
82
|
allowlist?: string[] | undefined;
|
|
83
83
|
commands?: string[] | undefined;
|
|
84
|
+
max_diff_bytes?: number | undefined;
|
|
84
85
|
skip_missing_npm_scripts?: boolean | undefined;
|
|
85
86
|
fail_fast?: boolean | undefined;
|
|
86
87
|
validate_after_agent_failure?: boolean | undefined;
|
|
87
88
|
validation_allowlist?: string[] | undefined;
|
|
88
89
|
restore_disallowed_changes?: boolean | undefined;
|
|
89
|
-
max_diff_bytes?: number | undefined;
|
|
90
90
|
allow_empty_diff?: boolean | undefined;
|
|
91
91
|
}>>;
|
|
92
92
|
caching: z.ZodOptional<z.ZodObject<{
|
|
@@ -131,11 +131,11 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
131
131
|
app_enabled: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
132
132
|
publish_mode: z.ZodOptional<z.ZodOptional<z.ZodEnum<["auto", "on", "off"]>>>;
|
|
133
133
|
}, "strip", z.ZodTypeAny, {
|
|
134
|
-
app_enabled?: boolean | undefined;
|
|
135
134
|
publish_mode?: "auto" | "off" | "on" | undefined;
|
|
136
|
-
}, {
|
|
137
135
|
app_enabled?: boolean | undefined;
|
|
136
|
+
}, {
|
|
138
137
|
publish_mode?: "auto" | "off" | "on" | undefined;
|
|
138
|
+
app_enabled?: boolean | undefined;
|
|
139
139
|
}>>;
|
|
140
140
|
docker: z.ZodOptional<z.ZodObject<{
|
|
141
141
|
image: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -211,12 +211,12 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
211
211
|
validation?: {
|
|
212
212
|
allowlist?: string[] | undefined;
|
|
213
213
|
commands?: string[] | undefined;
|
|
214
|
+
max_diff_bytes?: number | undefined;
|
|
214
215
|
skip_missing_npm_scripts?: boolean | undefined;
|
|
215
216
|
fail_fast?: boolean | undefined;
|
|
216
217
|
validate_after_agent_failure?: boolean | undefined;
|
|
217
218
|
validation_allowlist?: string[] | undefined;
|
|
218
219
|
restore_disallowed_changes?: boolean | undefined;
|
|
219
|
-
max_diff_bytes?: number | undefined;
|
|
220
220
|
allow_empty_diff?: boolean | undefined;
|
|
221
221
|
} | undefined;
|
|
222
222
|
debug?: {
|
|
@@ -234,9 +234,9 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
234
234
|
github_app_private_key_file?: string | undefined;
|
|
235
235
|
} | undefined;
|
|
236
236
|
agent?: {
|
|
237
|
+
timeout_seconds?: number | undefined;
|
|
237
238
|
model?: string | undefined;
|
|
238
239
|
provider?: string | undefined;
|
|
239
|
-
timeout_seconds?: number | undefined;
|
|
240
240
|
guardrails?: boolean | undefined;
|
|
241
241
|
} | undefined;
|
|
242
242
|
repo?: {
|
|
@@ -259,8 +259,8 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
259
259
|
max_bytes?: number | undefined;
|
|
260
260
|
} | undefined;
|
|
261
261
|
github?: {
|
|
262
|
-
app_enabled?: boolean | undefined;
|
|
263
262
|
publish_mode?: "auto" | "off" | "on" | undefined;
|
|
263
|
+
app_enabled?: boolean | undefined;
|
|
264
264
|
} | undefined;
|
|
265
265
|
docker?: {
|
|
266
266
|
image?: string | undefined;
|
|
@@ -284,12 +284,12 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
284
284
|
validation?: {
|
|
285
285
|
allowlist?: string[] | undefined;
|
|
286
286
|
commands?: string[] | undefined;
|
|
287
|
+
max_diff_bytes?: number | undefined;
|
|
287
288
|
skip_missing_npm_scripts?: boolean | undefined;
|
|
288
289
|
fail_fast?: boolean | undefined;
|
|
289
290
|
validate_after_agent_failure?: boolean | undefined;
|
|
290
291
|
validation_allowlist?: string[] | undefined;
|
|
291
292
|
restore_disallowed_changes?: boolean | undefined;
|
|
292
|
-
max_diff_bytes?: number | undefined;
|
|
293
293
|
allow_empty_diff?: boolean | undefined;
|
|
294
294
|
} | undefined;
|
|
295
295
|
debug?: {
|
|
@@ -307,9 +307,9 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
307
307
|
github_app_private_key_file?: string | undefined;
|
|
308
308
|
} | undefined;
|
|
309
309
|
agent?: {
|
|
310
|
+
timeout_seconds?: number | undefined;
|
|
310
311
|
model?: string | undefined;
|
|
311
312
|
provider?: string | undefined;
|
|
312
|
-
timeout_seconds?: number | undefined;
|
|
313
313
|
guardrails?: boolean | undefined;
|
|
314
314
|
} | undefined;
|
|
315
315
|
repo?: {
|
|
@@ -332,8 +332,8 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
332
332
|
max_bytes?: number | undefined;
|
|
333
333
|
} | undefined;
|
|
334
334
|
github?: {
|
|
335
|
-
app_enabled?: boolean | undefined;
|
|
336
335
|
publish_mode?: "auto" | "off" | "on" | undefined;
|
|
336
|
+
app_enabled?: boolean | undefined;
|
|
337
337
|
} | undefined;
|
|
338
338
|
docker?: {
|
|
339
339
|
image?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kaseki-api-routes.d.ts","sourceRoot":"","sources":["../src/kaseki-api-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAOlE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAU5D,OAAO,EAAE,eAAe,EAAkB,MAAM,qBAAqB,CAAC;AAStE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAI7C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"kaseki-api-routes.d.ts","sourceRoot":"","sources":["../src/kaseki-api-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAOlE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAU5D,OAAO,EAAE,eAAe,EAAkB,MAAM,qBAAqB,CAAC;AAStE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAI7C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAwR5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AA0PjE;;GAEG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,YAAY,EACvB,MAAM,EAAE,eAAe,EACvB,gBAAgB,EAAE,gBAAgB,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,cAIX,GACD,MAAM,CA8YR"}
|
|
@@ -54,46 +54,53 @@ function tailTextByLines(content, lineCount) {
|
|
|
54
54
|
const lines = content.replace(/\r\n/g, '\n').split('\n');
|
|
55
55
|
return lines.slice(-lineCount).join('\n').trim();
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
const checkoutDir = process.env.KASEKI_CHECKOUT_DIR || '/agents/kaseki-agent';
|
|
59
|
-
const checkoutRef = getTemplateCheckoutRef(checkoutDir);
|
|
60
|
-
const runScript = path.join(templateDir, 'run-kaseki.sh');
|
|
61
|
-
const missingFiles = REQUIRED_TEMPLATE_FILES.filter((file) => !fs.existsSync(path.join(templateDir, file)));
|
|
57
|
+
function validateTemplateRunScript(templateDir, runScript, templateRef, checkoutDir) {
|
|
62
58
|
if (!fs.existsSync(runScript)) {
|
|
63
59
|
return {
|
|
64
60
|
ok: false,
|
|
65
61
|
templateDir,
|
|
66
62
|
runScript,
|
|
67
63
|
checkoutDir,
|
|
68
|
-
checkoutRef,
|
|
64
|
+
checkoutRef: templateRef,
|
|
69
65
|
detail: `Missing template runner: ${runScript}`,
|
|
70
66
|
remediation: TEMPLATE_REMEDIATION,
|
|
71
67
|
};
|
|
72
68
|
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function validateTemplateFiles(templateDir, runScript, templateRef, checkoutDir) {
|
|
72
|
+
const missingFiles = REQUIRED_TEMPLATE_FILES.filter((file) => !fs.existsSync(path.join(templateDir, file)));
|
|
73
73
|
if (missingFiles.length > 0) {
|
|
74
74
|
return {
|
|
75
75
|
ok: false,
|
|
76
76
|
templateDir,
|
|
77
77
|
runScript,
|
|
78
78
|
checkoutDir,
|
|
79
|
-
checkoutRef,
|
|
79
|
+
checkoutRef: templateRef,
|
|
80
80
|
detail: `Template is incomplete at ${templateDir}; missing ${missingFiles.join(', ')}.`,
|
|
81
81
|
remediation: 'Run scripts/kaseki-activate.sh --controller bootstrap, or scripts/kaseki-setup-host.sh --fix before starting the API.',
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function runTemplateDoctor(runScript, checkoutDir) {
|
|
84
87
|
const activateScript = path.join(checkoutDir, 'scripts', 'kaseki-activate.sh');
|
|
85
88
|
const doctorArgs = fs.existsSync(activateScript)
|
|
86
89
|
? [activateScript, '--json', 'doctor']
|
|
87
90
|
: [runScript, '--doctor'];
|
|
88
|
-
|
|
89
|
-
const doctorResult = spawnSync(doctorArgs[0], doctorArgs.slice(1), {
|
|
91
|
+
return spawnSync(doctorArgs[0], doctorArgs.slice(1), {
|
|
90
92
|
cwd: fs.existsSync(checkoutDir) ? checkoutDir : undefined,
|
|
91
93
|
encoding: 'utf-8',
|
|
92
94
|
timeout: getTemplateDoctorTimeoutMs(),
|
|
93
95
|
maxBuffer: 128 * 1024,
|
|
94
96
|
});
|
|
97
|
+
}
|
|
98
|
+
function validateTemplateDoctor(doctorResult, templateDir, runScript, templateRef, checkoutDir) {
|
|
95
99
|
const stderr = `${doctorResult.stderr || ''}${doctorResult.error ? `\n${doctorResult.error.message}` : ''}`;
|
|
96
100
|
const doctorStderrTail = tailTextByLines(stderr, TEMPLATE_DOCTOR_STDERR_TAIL_LINES);
|
|
101
|
+
const doctorArgs = fs.existsSync(path.join(checkoutDir, 'scripts', 'kaseki-activate.sh'))
|
|
102
|
+
? `${path.join(checkoutDir, 'scripts', 'kaseki-activate.sh')} --json doctor`
|
|
103
|
+
: `${runScript} --doctor`;
|
|
97
104
|
if (doctorResult.error || doctorResult.status !== 0) {
|
|
98
105
|
const timedOut = doctorResult.error?.message.toLowerCase().includes('timeout') || doctorResult.signal === 'SIGTERM';
|
|
99
106
|
return {
|
|
@@ -101,27 +108,50 @@ function buildTemplateHealthStatus(templateDir = process.env.KASEKI_TEMPLATE_DIR
|
|
|
101
108
|
templateDir,
|
|
102
109
|
runScript,
|
|
103
110
|
checkoutDir,
|
|
104
|
-
checkoutRef,
|
|
105
|
-
doctorCommand,
|
|
111
|
+
checkoutRef: templateRef,
|
|
112
|
+
doctorCommand: doctorArgs,
|
|
106
113
|
doctorExitCode: doctorResult.status,
|
|
107
114
|
doctorSignal: doctorResult.signal,
|
|
108
115
|
doctorStderrTail,
|
|
109
116
|
detail: timedOut
|
|
110
|
-
? `Template doctor timed out after ${getTemplateDoctorTimeoutMs()}ms: ${
|
|
111
|
-
: `Template doctor failed: ${
|
|
117
|
+
? `Template doctor timed out after ${getTemplateDoctorTimeoutMs()}ms: ${doctorArgs}`
|
|
118
|
+
: `Template doctor failed: ${doctorArgs} exited with ${doctorResult.status ?? 'unknown'}`,
|
|
112
119
|
remediation: TEMPLATE_REMEDIATION,
|
|
113
120
|
};
|
|
114
121
|
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function buildTemplateHealthStatus(templateDir = process.env.KASEKI_TEMPLATE_DIR || '/agents/kaseki-template') {
|
|
125
|
+
const checkoutDir = process.env.KASEKI_CHECKOUT_DIR || '/agents/kaseki-agent';
|
|
126
|
+
const checkoutRef = getTemplateCheckoutRef(checkoutDir);
|
|
127
|
+
const runScript = path.join(templateDir, 'run-kaseki.sh');
|
|
128
|
+
// Check 1: Validate run script exists
|
|
129
|
+
let validation = validateTemplateRunScript(templateDir, runScript, checkoutRef, checkoutDir);
|
|
130
|
+
if (validation)
|
|
131
|
+
return validation;
|
|
132
|
+
// Check 2: Validate all required files exist
|
|
133
|
+
validation = validateTemplateFiles(templateDir, runScript, checkoutRef, checkoutDir);
|
|
134
|
+
if (validation)
|
|
135
|
+
return validation;
|
|
136
|
+
// Check 3: Run doctor check
|
|
137
|
+
const doctorResult = runTemplateDoctor(runScript, checkoutDir);
|
|
138
|
+
validation = validateTemplateDoctor(doctorResult, templateDir, runScript, checkoutRef, checkoutDir);
|
|
139
|
+
if (validation)
|
|
140
|
+
return validation;
|
|
141
|
+
// All checks passed
|
|
142
|
+
const doctorArgs = fs.existsSync(path.join(checkoutDir, 'scripts', 'kaseki-activate.sh'))
|
|
143
|
+
? `${path.join(checkoutDir, 'scripts', 'kaseki-activate.sh')} --json doctor`
|
|
144
|
+
: `${runScript} --doctor`;
|
|
115
145
|
return {
|
|
116
146
|
ok: true,
|
|
117
147
|
templateDir,
|
|
118
148
|
runScript,
|
|
119
149
|
checkoutDir,
|
|
120
150
|
checkoutRef,
|
|
121
|
-
doctorCommand,
|
|
151
|
+
doctorCommand: doctorArgs,
|
|
122
152
|
doctorExitCode: doctorResult.status,
|
|
123
153
|
doctorSignal: doctorResult.signal,
|
|
124
|
-
doctorStderrTail,
|
|
154
|
+
doctorStderrTail: '',
|
|
125
155
|
detail: `Template runner passed doctor check: ${runScript}`,
|
|
126
156
|
};
|
|
127
157
|
}
|
|
@@ -198,6 +228,52 @@ function inspectImageDigest(image) {
|
|
|
198
228
|
}
|
|
199
229
|
// Re-export from subprocess-helpers for backward compatibility with tests
|
|
200
230
|
export { classifyDockerFailure } from './lib/subprocess-helpers.js';
|
|
231
|
+
function parseMountInfo() {
|
|
232
|
+
try {
|
|
233
|
+
const mountInfoPath = process.env.KASEKI_MOUNTINFO_PATH || '/proc/self/mountinfo';
|
|
234
|
+
const content = fs.readFileSync(mountInfoPath, 'utf-8');
|
|
235
|
+
return content
|
|
236
|
+
.split(/\r?\n/)
|
|
237
|
+
.filter(Boolean)
|
|
238
|
+
.map((line) => {
|
|
239
|
+
const fields = line.split(' ');
|
|
240
|
+
return {
|
|
241
|
+
root: fields[3] || '',
|
|
242
|
+
mountPoint: fields[4] || '',
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function checkDeletedBindMounts(paths) {
|
|
251
|
+
const mountInfo = parseMountInfo();
|
|
252
|
+
const uniquePaths = [...new Set(paths.filter(Boolean))];
|
|
253
|
+
const deletedMounts = mountInfo.filter((mount) => {
|
|
254
|
+
const root = mount.root.toLowerCase();
|
|
255
|
+
if (!root.includes('deleted')) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return uniquePaths.some((targetPath) => (targetPath === mount.mountPoint || targetPath.startsWith(`${mount.mountPoint}/`)));
|
|
259
|
+
});
|
|
260
|
+
if (deletedMounts.length === 0) {
|
|
261
|
+
return {
|
|
262
|
+
name: 'bind-mounts',
|
|
263
|
+
ok: true,
|
|
264
|
+
detail: 'No deleted bind mounts detected for Kaseki paths.',
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const details = deletedMounts
|
|
268
|
+
.map((mount) => `${mount.mountPoint} is backed by deleted source ${mount.root}`)
|
|
269
|
+
.join('; ');
|
|
270
|
+
return {
|
|
271
|
+
name: 'bind-mounts',
|
|
272
|
+
ok: false,
|
|
273
|
+
detail: details,
|
|
274
|
+
remediation: 'Recreate the missing host directory, then recreate the kaseki-api container so Docker binds the live path. For the default layout: sudo /agents/kaseki-agent/scripts/kaseki-setup-host.sh --fix && docker compose up -d --force-recreate.',
|
|
275
|
+
};
|
|
276
|
+
}
|
|
201
277
|
function checkOpenRouterKey() {
|
|
202
278
|
const keyValue = readHostSecret('openrouter_api_key');
|
|
203
279
|
if (keyValue) {
|
|
@@ -282,11 +358,13 @@ function isGitHubAppReady() {
|
|
|
282
358
|
}
|
|
283
359
|
function buildPreflightResponse(config) {
|
|
284
360
|
const templateDir = process.env.KASEKI_TEMPLATE_DIR || '/agents/kaseki-template';
|
|
361
|
+
const secretsDir = process.env.KASEKI_SECRETS_DIR || '/agents/secrets';
|
|
285
362
|
const image = readKasekiImage(templateDir);
|
|
286
363
|
const templateImageDigest = readFirstLine(path.join(templateDir, '.kaseki-image-digest')) || inspectImageDigest(image);
|
|
287
364
|
const checkoutDir = process.env.KASEKI_CHECKOUT_DIR || '/agents/kaseki-agent';
|
|
288
365
|
const templateRef = getTemplateCheckoutRef(checkoutDir);
|
|
289
366
|
const checks = [];
|
|
367
|
+
checks.push(checkDeletedBindMounts([config.resultsDir, templateDir, checkoutDir, secretsDir]));
|
|
290
368
|
try {
|
|
291
369
|
fs.accessSync(config.resultsDir, fs.constants.R_OK | fs.constants.W_OK);
|
|
292
370
|
checks.push({ name: 'results-dir', ok: true, detail: `${config.resultsDir} is readable and writable.` });
|