@cyanautomation/kaseki-agent 1.27.5 → 1.29.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 (34) hide show
  1. package/README.md +20 -0
  2. package/dist/__test-utils/openapi-assertions.d.ts +39 -0
  3. package/dist/__test-utils/openapi-assertions.d.ts.map +1 -0
  4. package/dist/__test-utils/openapi-assertions.js +101 -0
  5. package/dist/__test-utils/openapi-assertions.js.map +1 -0
  6. package/dist/cli/commands/InitCommand.d.ts.map +1 -1
  7. package/dist/cli/commands/InitCommand.js +3 -0
  8. package/dist/cli/commands/InitCommand.js.map +1 -1
  9. package/dist/config/ConfigManager.d.ts +12 -12
  10. package/dist/kaseki-api-routes.d.ts.map +1 -1
  11. package/dist/kaseki-api-routes.js +93 -15
  12. package/dist/kaseki-api-routes.js.map +1 -1
  13. package/dist/kaseki-api-types.d.ts +35 -5
  14. package/dist/kaseki-api-types.d.ts.map +1 -1
  15. package/dist/kaseki-api-types.js +29 -1
  16. package/dist/kaseki-api-types.js.map +1 -1
  17. package/dist/secrets/host-secrets-reader.d.ts +1 -1
  18. package/dist/secrets/host-secrets-reader.d.ts.map +1 -1
  19. package/dist/secrets/host-secrets-reader.js +6 -4
  20. package/dist/secrets/host-secrets-reader.js.map +1 -1
  21. package/dist/setup/SetupWizard.d.ts +18 -1
  22. package/dist/setup/SetupWizard.d.ts.map +1 -1
  23. package/dist/setup/SetupWizard.js +128 -6
  24. package/dist/setup/SetupWizard.js.map +1 -1
  25. package/package.json +1 -1
  26. package/scripts/docker-entrypoint.sh +17 -4
  27. package/scripts/kaseki-init-container.sh +99 -0
  28. package/scripts/kaseki-preflight-docker-compose.sh +296 -0
  29. package/scripts/kaseki-setup-host.sh +49 -6
  30. package/scripts/startup-checks.sh +101 -2
  31. package/dist/setup/env-defaults.d.ts +0 -86
  32. package/dist/setup/env-defaults.d.ts.map +0 -1
  33. package/dist/setup/env-defaults.js +0 -403
  34. 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;IAkC9C;;OAEG;IACH,OAAO,CAAC,SAAS;IA2CjB;;OAEG;IACH,OAAO,CAAC,cAAc;CA4DvB"}
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;YAEtD,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;aACb,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuCX,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"}
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;AAuO5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAmMjE;;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"}
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 buildTemplateHealthStatus(templateDir = process.env.KASEKI_TEMPLATE_DIR || '/agents/kaseki-template') {
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
- const doctorCommand = doctorArgs.join(' ');
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: ${doctorCommand}`
111
- : `Template doctor failed: ${doctorCommand} exited with ${doctorResult.status ?? 'unknown'}`,
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.` });