@trydreamstate/cli 1.3.2 → 1.3.4
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 +36 -16
- package/agent-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-plugin/.codex-plugin/plugin.json +1 -1
- package/agent-plugin/hooks/approve-readonly.sh +15 -0
- package/agent-plugin/hooks/hooks.json +17 -0
- package/agent-plugin/skills/crm/SKILL.md +2 -2
- package/agent-plugin/skills/diagnostics/SKILL.md +3 -1
- package/agent-plugin/skills/dreamstate/SKILL.md +15 -5
- package/agent-plugin/skills/first-win/SKILL.md +2 -2
- package/agent-plugin/skills/inbox-replies/SKILL.md +3 -1
- package/agent-plugin/skills/knowledge/SKILL.md +3 -5
- package/agent-plugin/skills/linkedin-posts/SKILL.md +3 -1
- package/agent-plugin/skills/linkedin-warm-signals/SKILL.md +2 -2
- package/agent-plugin/skills/list-building/SKILL.md +5 -10
- package/agent-plugin/skills/list-building/column-authoring.md +1 -1
- package/agent-plugin/skills/list-building/sourcing.md +2 -2
- package/agent-plugin/skills/outreach/SKILL.md +2 -2
- package/agent-plugin/skills/outreach/steps-and-timing.md +1 -1
- package/agent-plugin/skills/plays/SKILL.md +3 -3
- package/agent-plugin/skills/reddit-posts/SKILL.md +3 -1
- package/agent-plugin/skills/skill-authoring/SKILL.md +3 -1
- package/agent-plugin/skills/social/SKILL.md +4 -6
- package/agent-plugin/skills/visibility/SKILL.md +2 -6
- package/agent-plugin/skills/workflows/SKILL.md +3 -3
- package/agent-plugin/skills/workflows/lifecycle-and-enrollment.md +1 -1
- package/agent-plugin/skills/worksheet-tidy/SKILL.md +3 -1
- package/agent-plugin/skills/writing/SKILL.md +3 -5
- package/agent-plugin/skills/x-posts/SKILL.md +3 -1
- package/dist/agentGuidance.generated.json +35 -0
- package/dist/capabilityPosture.d.ts +12 -0
- package/dist/capabilityPosture.d.ts.map +1 -0
- package/dist/capabilityPosture.js +39 -0
- package/dist/client.d.ts +33 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +155 -64
- package/dist/commandTable.d.ts +26 -0
- package/dist/commandTable.d.ts.map +1 -0
- package/dist/commandTable.js +54 -0
- package/dist/commands/sequences.d.ts +3 -2
- package/dist/commands/sequences.d.ts.map +1 -1
- package/dist/commands/sequences.js +17 -34
- package/dist/commands/shared.d.ts +4 -26
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +136 -158
- package/dist/commands/workflows.d.ts +3 -2
- package/dist/commands/workflows.d.ts.map +1 -1
- package/dist/commands/workflows.js +17 -39
- package/dist/errors.d.ts +74 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +84 -0
- package/dist/gatedRun.d.ts +79 -0
- package/dist/gatedRun.d.ts.map +1 -0
- package/dist/gatedRun.js +346 -0
- package/dist/generated/packVerbs.generated.json +492 -0
- package/dist/generated/runContract.generated.d.ts +4 -0
- package/dist/generated/runContract.generated.d.ts.map +1 -0
- package/dist/generated/runContract.generated.js +7 -0
- package/dist/idempotency.d.ts +38 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +106 -0
- package/dist/index.d.ts +22 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +405 -378
- package/dist/registryManifest.d.ts +6 -0
- package/dist/registryManifest.d.ts.map +1 -0
- package/dist/registryManifest.js +66 -0
- package/dist/runContract.d.ts +10 -0
- package/dist/runContract.d.ts.map +1 -0
- package/dist/runContract.js +13 -0
- package/dist/runWait.d.ts +2 -2
- package/dist/runWait.d.ts.map +1 -1
- package/dist/runWait.js +3 -14
- package/dist/schemaCoercion.d.ts +20 -0
- package/dist/schemaCoercion.d.ts.map +1 -0
- package/dist/schemaCoercion.js +123 -0
- package/dist/skillInstaller.d.ts +40 -0
- package/dist/skillInstaller.d.ts.map +1 -1
- package/dist/skillInstaller.js +108 -9
- package/dist/tableFilePreview.d.ts +14 -0
- package/dist/tableFilePreview.d.ts.map +1 -1
- package/dist/tableFilePreview.js +19 -8
- package/dist/tableFileReader.d.ts +26 -0
- package/dist/tableFileReader.d.ts.map +1 -0
- package/dist/tableFileReader.js +108 -0
- package/dist/tablesImport.d.ts +57 -0
- package/dist/tablesImport.d.ts.map +1 -0
- package/dist/tablesImport.js +263 -0
- package/dist/turnCache.d.ts +14 -1
- package/dist/turnCache.d.ts.map +1 -1
- package/dist/turnCache.js +25 -8
- package/package.json +6 -3
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CapabilityPosture } from './capabilityPosture';
|
|
2
|
+
export declare function lookupPosture(capabilityId: string): CapabilityPosture | null;
|
|
3
|
+
export declare function rememberPosture(capabilityId: string, posture: CapabilityPosture): void;
|
|
4
|
+
/** Records the hash from a response. A change clears cached postures. */
|
|
5
|
+
export declare function noteRegistryHash(hash: string | null): void;
|
|
6
|
+
//# sourceMappingURL=registryManifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registryManifest.d.ts","sourceRoot":"","sources":["../src/registryManifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAuD7D,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAE5E;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAItF;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAK1D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lookupPosture = lookupPosture;
|
|
4
|
+
exports.rememberPosture = rememberPosture;
|
|
5
|
+
exports.noteRegistryHash = noteRegistryHash;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_os_1 = require("node:os");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
function manifestPath(home = (0, node_os_1.homedir)()) {
|
|
10
|
+
return (0, node_path_1.join)(home, '.dreamstate', 'registry-manifest.json');
|
|
11
|
+
}
|
|
12
|
+
function empty() {
|
|
13
|
+
return { registry_hash: null, postures: {} };
|
|
14
|
+
}
|
|
15
|
+
function readManifest() {
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(manifestPath(), 'utf8'));
|
|
18
|
+
const root = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
19
|
+
if (!root)
|
|
20
|
+
return empty();
|
|
21
|
+
const postures = {};
|
|
22
|
+
const raw = root.postures && typeof root.postures === 'object' && !Array.isArray(root.postures)
|
|
23
|
+
? root.postures
|
|
24
|
+
: {};
|
|
25
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
26
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
27
|
+
continue;
|
|
28
|
+
const posture = value;
|
|
29
|
+
postures[id] = { inlineRead: posture.inlineRead === true, returnsRunId: posture.returnsRunId === true };
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
registry_hash: typeof root.registry_hash === 'string' && root.registry_hash ? root.registry_hash : null,
|
|
33
|
+
postures,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return empty();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function writeManifest(manifest) {
|
|
41
|
+
try {
|
|
42
|
+
const path = manifestPath();
|
|
43
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(path), { recursive: true });
|
|
44
|
+
(0, node_fs_1.writeFileSync)(path, `${JSON.stringify(manifest)}\n`, 'utf8');
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Cache only. A request still runs when the home directory is not writable.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function lookupPosture(capabilityId) {
|
|
51
|
+
return readManifest().postures[capabilityId] ?? null;
|
|
52
|
+
}
|
|
53
|
+
function rememberPosture(capabilityId, posture) {
|
|
54
|
+
const manifest = readManifest();
|
|
55
|
+
manifest.postures[capabilityId] = posture;
|
|
56
|
+
writeManifest(manifest);
|
|
57
|
+
}
|
|
58
|
+
/** Records the hash from a response. A change clears cached postures. */
|
|
59
|
+
function noteRegistryHash(hash) {
|
|
60
|
+
if (!hash)
|
|
61
|
+
return;
|
|
62
|
+
const manifest = readManifest();
|
|
63
|
+
if (manifest.registry_hash === hash)
|
|
64
|
+
return;
|
|
65
|
+
writeManifest({ registry_hash: hash, postures: manifest.registry_hash ? {} : manifest.postures });
|
|
66
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-door constants. Frozen names are RUN_MODES, QUOTE_HASH_PATTERN and
|
|
3
|
+
* IDEMPOTENCY_KEY_MAX_LENGTH. The source is packages/types/src/agentSurface.ts.
|
|
4
|
+
* The published CLI cannot depend on the unpublished types package, so the
|
|
5
|
+
* values are generated into src/generated/runContract.generated.ts.
|
|
6
|
+
*/
|
|
7
|
+
import { IDEMPOTENCY_KEY_MAX_LENGTH, QUOTE_HASH_PATTERN, RUN_MODES } from './generated/runContract.generated';
|
|
8
|
+
export { IDEMPOTENCY_KEY_MAX_LENGTH, QUOTE_HASH_PATTERN, RUN_MODES };
|
|
9
|
+
export type RunMode = (typeof RUN_MODES)[number];
|
|
10
|
+
//# sourceMappingURL=runContract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runContract.d.ts","sourceRoot":"","sources":["../src/runContract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,EAClB,SAAS,EACV,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC;AACrE,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RUN_MODES = exports.QUOTE_HASH_PATTERN = exports.IDEMPOTENCY_KEY_MAX_LENGTH = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Run-door constants. Frozen names are RUN_MODES, QUOTE_HASH_PATTERN and
|
|
6
|
+
* IDEMPOTENCY_KEY_MAX_LENGTH. The source is packages/types/src/agentSurface.ts.
|
|
7
|
+
* The published CLI cannot depend on the unpublished types package, so the
|
|
8
|
+
* values are generated into src/generated/runContract.generated.ts.
|
|
9
|
+
*/
|
|
10
|
+
const runContract_generated_1 = require("./generated/runContract.generated");
|
|
11
|
+
Object.defineProperty(exports, "IDEMPOTENCY_KEY_MAX_LENGTH", { enumerable: true, get: function () { return runContract_generated_1.IDEMPOTENCY_KEY_MAX_LENGTH; } });
|
|
12
|
+
Object.defineProperty(exports, "QUOTE_HASH_PATTERN", { enumerable: true, get: function () { return runContract_generated_1.QUOTE_HASH_PATTERN; } });
|
|
13
|
+
Object.defineProperty(exports, "RUN_MODES", { enumerable: true, get: function () { return runContract_generated_1.RUN_MODES; } });
|
package/dist/runWait.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DreamstateClient } from './client';
|
|
2
|
-
|
|
3
|
-
export declare
|
|
2
|
+
/** The wait ran out with the run still active; the latest run envelope is printed. */
|
|
3
|
+
export declare const RUN_WAIT_TIMEOUT_EXIT_CODE: number;
|
|
4
4
|
export interface RunWaitResult {
|
|
5
5
|
value: unknown;
|
|
6
6
|
timedOut: boolean;
|
package/dist/runWait.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runWait.d.ts","sourceRoot":"","sources":["../src/runWait.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"runWait.d.ts","sourceRoot":"","sources":["../src/runWait.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAQjD,sFAAsF;AACtF,eAAO,MAAM,0BAA0B,EAAE,MAAyB,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AA+BD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAC7C,OAAO,CAAC,aAAa,CAAC,CAmBxB"}
|
package/dist/runWait.js
CHANGED
|
@@ -1,25 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RUN_WAIT_TIMEOUT_EXIT_CODE = void 0;
|
|
4
|
-
exports.columnRunReturnsRunId = columnRunReturnsRunId;
|
|
5
4
|
exports.waitForRun = waitForRun;
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
6
|
const TERMINAL_STATUSES = new Set([
|
|
7
7
|
'succeeded', 'completed', 'completed_with_errors', 'failed', 'cancelled', 'canceled', 'partially_completed',
|
|
8
8
|
'timed_out', 'rejected', 'awaiting_approval', 'awaiting_input', 'waiting', 'waiting_approval', 'approval_required',
|
|
9
9
|
]);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'tables.columns.run',
|
|
13
|
-
'tables.columns.run_all',
|
|
14
|
-
'tables.columns.run_remaining',
|
|
15
|
-
]);
|
|
16
|
-
// timing:async column runs. The tools response is the durable run id. Waiting
|
|
17
|
-
// folds every provider row into the command. Progress and final cells are
|
|
18
|
-
// runs_get and rows.query. Other mutations still wait so the next command can
|
|
19
|
-
// read steps[0].outputs.
|
|
20
|
-
function columnRunReturnsRunId(capabilityId) {
|
|
21
|
-
return COLUMN_RUN_HAND_OFF.has(capabilityId);
|
|
22
|
-
}
|
|
10
|
+
/** The wait ran out with the run still active; the latest run envelope is printed. */
|
|
11
|
+
exports.RUN_WAIT_TIMEOUT_EXIT_CODE = errors_1.CLI_EXIT.TIMEOUT;
|
|
23
12
|
function runFromEnvelope(value) {
|
|
24
13
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
25
14
|
return null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface CoercionResult {
|
|
2
|
+
params: Record<string, unknown>;
|
|
3
|
+
/** Property names whose string value was converted. */
|
|
4
|
+
coerced: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pack verbs intentionally do not carry a second copy of a capability's required
|
|
8
|
+
* fields. `tools get` is source of truth: reject an unknown canonical flag and
|
|
9
|
+
* report fields that schema currently requires after the live contract is read.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assertParamsMatchSchema(params: Record<string, unknown>, schema: unknown): void;
|
|
12
|
+
/**
|
|
13
|
+
* Runtime schema coercion for flag-built params. The CLI's pack verbs take their
|
|
14
|
+
* values from flags, and every flag arrives as a string; a numeric property such
|
|
15
|
+
* as max_new_enrollments_per_day was sent as "40" and refused. The type is read
|
|
16
|
+
* from the capability's live input schema (tools get), never from a hand-kept
|
|
17
|
+
* list, so a new numeric field works on the day the catalog adds it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function coerceParamsToSchema(params: Record<string, unknown>, schema: unknown): CoercionResult;
|
|
20
|
+
//# sourceMappingURL=schemaCoercion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaCoercion.d.ts","sourceRoot":"","sources":["../src/schemaCoercion.ts"],"names":[],"mappings":"AAoEA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAS9F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,cAAc,CAerG"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertParamsMatchSchema = assertParamsMatchSchema;
|
|
4
|
+
exports.coerceParamsToSchema = coerceParamsToSchema;
|
|
5
|
+
function isObject(value) {
|
|
6
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
/** Follows a local `#/$defs/x` or `#/definitions/x` pointer (tools get hoists repeated subschemas there). */
|
|
9
|
+
function resolveRef(node, root, depth = 0) {
|
|
10
|
+
const ref = node.$ref;
|
|
11
|
+
if (typeof ref !== 'string' || !ref.startsWith('#/') || depth > 8)
|
|
12
|
+
return node;
|
|
13
|
+
let current = root;
|
|
14
|
+
for (const part of ref.slice(2).split('/')) {
|
|
15
|
+
current = isObject(current) ? current[decodeURIComponent(part)] : undefined;
|
|
16
|
+
}
|
|
17
|
+
return isObject(current) ? resolveRef(current, root, depth + 1) : node;
|
|
18
|
+
}
|
|
19
|
+
/** Every JSON type a (possibly union) schema accepts. */
|
|
20
|
+
function acceptedTypes(node, root, depth = 0) {
|
|
21
|
+
const types = new Set();
|
|
22
|
+
if (!isObject(node) || depth > 8)
|
|
23
|
+
return types;
|
|
24
|
+
const resolved = resolveRef(node, root);
|
|
25
|
+
const declared = resolved.type;
|
|
26
|
+
for (const type of Array.isArray(declared) ? declared : declared === undefined ? [] : [declared]) {
|
|
27
|
+
if (typeof type === 'string')
|
|
28
|
+
types.add(type);
|
|
29
|
+
}
|
|
30
|
+
for (const key of ['anyOf', 'oneOf']) {
|
|
31
|
+
const branches = resolved[key];
|
|
32
|
+
if (Array.isArray(branches))
|
|
33
|
+
for (const branch of branches)
|
|
34
|
+
acceptedTypes(branch, root, depth + 1).forEach((type) => types.add(type));
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(resolved.allOf)) {
|
|
37
|
+
for (const branch of resolved.allOf)
|
|
38
|
+
acceptedTypes(branch, root, depth + 1).forEach((type) => types.add(type));
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(resolved.enum) && resolved.enum.some((member) => typeof member === 'string'))
|
|
41
|
+
types.add('string');
|
|
42
|
+
return types;
|
|
43
|
+
}
|
|
44
|
+
const NUMBER_TEXT = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
45
|
+
/**
|
|
46
|
+
* One flag value, as the shell delivered it (a string), turned into the type the
|
|
47
|
+
* capability's input schema declares. A string-typed property is never touched,
|
|
48
|
+
* so a value the author meant as text (a name that looks like a number) survives.
|
|
49
|
+
*/
|
|
50
|
+
function coerceValue(value, types) {
|
|
51
|
+
if (types.has('string') || types.size === 0)
|
|
52
|
+
return value;
|
|
53
|
+
const text = value.trim();
|
|
54
|
+
if ((types.has('integer') || types.has('number')) && NUMBER_TEXT.test(text)) {
|
|
55
|
+
const parsed = Number(text);
|
|
56
|
+
if (Number.isFinite(parsed) && (types.has('number') || Number.isInteger(parsed)))
|
|
57
|
+
return parsed;
|
|
58
|
+
}
|
|
59
|
+
if (types.has('boolean')) {
|
|
60
|
+
if (text === 'true')
|
|
61
|
+
return true;
|
|
62
|
+
if (text === 'false')
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (types.has('array') || types.has('object')) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = JSON.parse(text);
|
|
68
|
+
if (Array.isArray(parsed) ? types.has('array') : isObject(parsed) && types.has('object'))
|
|
69
|
+
return parsed;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Not JSON: leave it, and the server's schema refusal names the field.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (types.has('null') && text === 'null')
|
|
76
|
+
return null;
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Pack verbs intentionally do not carry a second copy of a capability's required
|
|
81
|
+
* fields. `tools get` is source of truth: reject an unknown canonical flag and
|
|
82
|
+
* report fields that schema currently requires after the live contract is read.
|
|
83
|
+
*/
|
|
84
|
+
function assertParamsMatchSchema(params, schema) {
|
|
85
|
+
if (!isObject(schema) || !isObject(schema.properties))
|
|
86
|
+
return;
|
|
87
|
+
const properties = schema.properties;
|
|
88
|
+
if (Object.keys(properties).length === 0)
|
|
89
|
+
return;
|
|
90
|
+
const unknown = Object.keys(params).filter((key) => !(key in properties));
|
|
91
|
+
if (unknown.length)
|
|
92
|
+
throw new Error(`live schema does not declare parameter(s): ${unknown.join(', ')}`);
|
|
93
|
+
const required = Array.isArray(schema.required) ? schema.required.filter((key) => typeof key === 'string') : [];
|
|
94
|
+
const missing = required.filter((key) => params[key] === undefined);
|
|
95
|
+
if (missing.length)
|
|
96
|
+
throw new Error(`live schema requires parameter(s): ${missing.join(', ')}`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Runtime schema coercion for flag-built params. The CLI's pack verbs take their
|
|
100
|
+
* values from flags, and every flag arrives as a string; a numeric property such
|
|
101
|
+
* as max_new_enrollments_per_day was sent as "40" and refused. The type is read
|
|
102
|
+
* from the capability's live input schema (tools get), never from a hand-kept
|
|
103
|
+
* list, so a new numeric field works on the day the catalog adds it.
|
|
104
|
+
*/
|
|
105
|
+
function coerceParamsToSchema(params, schema) {
|
|
106
|
+
if (!isObject(schema) || !isObject(schema.properties))
|
|
107
|
+
return { params, coerced: [] };
|
|
108
|
+
const out = { ...params };
|
|
109
|
+
const coerced = [];
|
|
110
|
+
for (const [key, value] of Object.entries(params)) {
|
|
111
|
+
if (typeof value !== 'string')
|
|
112
|
+
continue;
|
|
113
|
+
const property = schema.properties[key];
|
|
114
|
+
if (!isObject(property))
|
|
115
|
+
continue;
|
|
116
|
+
const next = coerceValue(value, acceptedTypes(property, schema));
|
|
117
|
+
if (next !== value) {
|
|
118
|
+
out[key] = next;
|
|
119
|
+
coerced.push(key);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { params: out, coerced };
|
|
123
|
+
}
|
package/dist/skillInstaller.d.ts
CHANGED
|
@@ -10,6 +10,13 @@ export interface HostedSkill {
|
|
|
10
10
|
name: string;
|
|
11
11
|
content: string;
|
|
12
12
|
}>;
|
|
13
|
+
/** The server's revision of SKILL.md; part of the content stamp doctor compares. */
|
|
14
|
+
revision_number?: number;
|
|
15
|
+
/** Supporting pages the server lists for this skill, with their revisions. */
|
|
16
|
+
files?: Array<{
|
|
17
|
+
path: string;
|
|
18
|
+
revision_number?: number;
|
|
19
|
+
}>;
|
|
13
20
|
}
|
|
14
21
|
export interface SkillInstallOptions {
|
|
15
22
|
agents: readonly SkillInstallAgent[];
|
|
@@ -23,6 +30,15 @@ export interface SkillInstallOptions {
|
|
|
23
30
|
export declare function canonicalSkillsDirectory(homeDirectory?: string, project?: boolean, cwd?: string): string;
|
|
24
31
|
export declare function skillInstallDirectory(agent: SkillInstallAgent, homeDirectory?: string, project?: boolean, cwd?: string): string;
|
|
25
32
|
export declare function detectInstalledSkillAgents(homeDirectory?: string): Promise<Array<'codex' | 'claude-code' | 'cursor'>>;
|
|
33
|
+
/**
|
|
34
|
+
* What identifies one skill's live content: its text and frontmatter, the server's
|
|
35
|
+
* revision of it, and the supporting pages with theirs. Install stamps this into
|
|
36
|
+
* every file it writes; `skills doctor` recomputes it from the live skills, so a
|
|
37
|
+
* skill that changed on the server is stale however recently it was installed.
|
|
38
|
+
*/
|
|
39
|
+
export declare function skillContentHash(skill: HostedSkill): string;
|
|
40
|
+
/** Version of the whole skill set, stamped as `skills=` in every installed file. */
|
|
41
|
+
export declare function skillIndexVersion(skills: readonly HostedSkill[]): string;
|
|
26
42
|
export declare function renderSkillMarkdown(skill: HostedSkill, provenance: {
|
|
27
43
|
workspaceId: string;
|
|
28
44
|
indexVersion: string;
|
|
@@ -48,4 +64,28 @@ export declare function inspectSkillInstallers(agents: readonly SkillInstallAgen
|
|
|
48
64
|
}>;
|
|
49
65
|
provenance_age_ms: number | null;
|
|
50
66
|
}>>;
|
|
67
|
+
export interface SkillDrift {
|
|
68
|
+
/** Installed skill directories found under the canonical skills directory. */
|
|
69
|
+
installed_skill_ids: string[];
|
|
70
|
+
live_skill_ids: string[];
|
|
71
|
+
/** Live skills with no installed copy. */
|
|
72
|
+
missing: string[];
|
|
73
|
+
/** Installed Dreamstate skills the server no longer lists. */
|
|
74
|
+
extra: string[];
|
|
75
|
+
/** Installed skills whose content stamp differs from the live content. */
|
|
76
|
+
stale: Array<{
|
|
77
|
+
id: string;
|
|
78
|
+
installed: string | null;
|
|
79
|
+
live: string;
|
|
80
|
+
}>;
|
|
81
|
+
in_sync: boolean;
|
|
82
|
+
/** The command that brings the install up to date. */
|
|
83
|
+
refresh_command: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Compares what is installed with the live skills, by content stamp and not by age.
|
|
87
|
+
* An install an hour old that predates a server-side edit is stale; one from last
|
|
88
|
+
* month that nothing has changed since is current.
|
|
89
|
+
*/
|
|
90
|
+
export declare function compareInstalledSkills(live: readonly HostedSkill[], homeDirectory?: string, project?: boolean, cwd?: string): Promise<SkillDrift>;
|
|
51
91
|
//# sourceMappingURL=skillInstaller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skillInstaller.d.ts","sourceRoot":"","sources":["../src/skillInstaller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skillInstaller.d.ts","sourceRoot":"","sources":["../src/skillInstaller.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,oBAAoB,+EAAgF,CAAC;AAClH,MAAM,MAAM,iBAAiB,GAAG,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAChD,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,oFAAoF;IACpF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,wBAAgB,wBAAwB,CAAC,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,MAAM,CAEhH;AAiBD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,iBAAiB,EAAE,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,MAAM,CAIvI;AAQD,wBAAsB,0BAA0B,CAAC,aAAa,SAAY,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC,CAAC,CAM9H;AAeD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAS3D;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAIxE;AAwBD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAczH;AAkDD,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,QAAQ,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAgB1N;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,WAAW,CAO3D;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,EAAE,aAAa,SAAY,EAAE,OAAO,UAAQ,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC,CAkC1W;AAED,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0EAA0E;IAC1E,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;CACzB;AAID;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,aAAa,SAAY,EACzB,OAAO,UAAQ,EACf,GAAG,SAAgB,GAClB,OAAO,CAAC,UAAU,CAAC,CA6BrB"}
|
package/dist/skillInstaller.js
CHANGED
|
@@ -32,23 +32,32 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
exports.SKILL_INSTALL_AGENTS = void 0;
|
|
37
40
|
exports.canonicalSkillsDirectory = canonicalSkillsDirectory;
|
|
38
41
|
exports.skillInstallDirectory = skillInstallDirectory;
|
|
39
42
|
exports.detectInstalledSkillAgents = detectInstalledSkillAgents;
|
|
43
|
+
exports.skillContentHash = skillContentHash;
|
|
44
|
+
exports.skillIndexVersion = skillIndexVersion;
|
|
40
45
|
exports.renderSkillMarkdown = renderSkillMarkdown;
|
|
41
46
|
exports.installSkills = installSkills;
|
|
42
47
|
exports.routerSkill = routerSkill;
|
|
43
48
|
exports.inspectSkillInstallers = inspectSkillInstallers;
|
|
49
|
+
exports.compareInstalledSkills = compareInstalledSkills;
|
|
44
50
|
const promises_1 = require("node:fs/promises");
|
|
45
51
|
const node_fs_1 = require("node:fs");
|
|
46
52
|
const node_crypto_1 = require("node:crypto");
|
|
47
53
|
const node_os_1 = require("node:os");
|
|
48
54
|
const node_path_1 = require("node:path");
|
|
49
|
-
const
|
|
55
|
+
const agentGuidance_generated_json_1 = __importDefault(require("./agentGuidance.generated.json"));
|
|
56
|
+
const errors_1 = require("./errors");
|
|
57
|
+
const idempotency_1 = require("./idempotency");
|
|
50
58
|
exports.SKILL_INSTALL_AGENTS = ['codex', 'claude-code', 'cursor', 'opencode', 'hermes', 'openclaw'];
|
|
51
59
|
const allowedTools = 'Bash(dreamstate *), Bash(jq *)';
|
|
60
|
+
const PROVENANCE_MARKER = '<!-- dreamstate provenance:';
|
|
52
61
|
const safeId = /^[a-z0-9][a-z0-9_-]*$/i;
|
|
53
62
|
function canonicalSkillsDirectory(homeDirectory = (0, node_os_1.homedir)(), project = false, cwd = process.cwd()) {
|
|
54
63
|
return project ? (0, node_path_1.join)(cwd, '.agents', 'skills') : (0, node_path_1.join)(homeDirectory, '.agents', 'skills');
|
|
@@ -103,14 +112,42 @@ async function agentInstalled(agent, homeDirectory, project, cwd) {
|
|
|
103
112
|
return false;
|
|
104
113
|
}
|
|
105
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* What identifies one skill's live content: its text and frontmatter, the server's
|
|
117
|
+
* revision of it, and the supporting pages with theirs. Install stamps this into
|
|
118
|
+
* every file it writes; `skills doctor` recomputes it from the live skills, so a
|
|
119
|
+
* skill that changed on the server is stale however recently it was installed.
|
|
120
|
+
*/
|
|
121
|
+
function skillContentHash(skill) {
|
|
122
|
+
return (0, node_crypto_1.createHash)('sha256').update((0, idempotency_1.stableJson)({
|
|
123
|
+
id: skill.id,
|
|
124
|
+
description: skill.description,
|
|
125
|
+
body: skill.body,
|
|
126
|
+
frontmatter: skill.frontmatter ?? {},
|
|
127
|
+
revision_number: skill.revision_number ?? null,
|
|
128
|
+
files: [...(skill.files ?? [])].map((file) => ({ path: file.path, revision_number: file.revision_number ?? null })).sort((a, b) => a.path.localeCompare(b.path)),
|
|
129
|
+
})).digest('hex').slice(0, 16);
|
|
130
|
+
}
|
|
131
|
+
/** Version of the whole skill set, stamped as `skills=` in every installed file. */
|
|
132
|
+
function skillIndexVersion(skills) {
|
|
133
|
+
return (0, node_crypto_1.createHash)('sha256')
|
|
134
|
+
.update(JSON.stringify(skills.map((skill) => [skill.id, skillContentHash(skill)])))
|
|
135
|
+
.digest('hex').slice(0, 16);
|
|
136
|
+
}
|
|
106
137
|
function yamlValue(value) { return JSON.stringify(value); }
|
|
107
138
|
function skillName(id) {
|
|
108
139
|
if (!safeId.test(id))
|
|
109
|
-
throw new
|
|
140
|
+
throw new errors_1.CliUsageError('Dreamstate API returned an invalid skill id.');
|
|
110
141
|
return id === 'router' ? 'dreamstate' : `dreamstate-${id}`;
|
|
111
142
|
}
|
|
143
|
+
// The router steps and the paid-run consent rule are not written here. They come from
|
|
144
|
+
// agentGuidance.generated.json, which packages/cli/scripts/build-agent-plugin.mjs generates
|
|
145
|
+
// from the same source as the plugin router and the server's MCP instructions.
|
|
146
|
+
function routerStepLines() {
|
|
147
|
+
return agentGuidance_generated_json_1.default.router_steps.map((step, index) => `${index + 1}. \`${step.cli}\` (MCP \`${step.mcp}\`) ${step.text}`).join('\n');
|
|
148
|
+
}
|
|
112
149
|
function commandGuide(packs) {
|
|
113
|
-
return `## How to run this in Dreamstate\n\
|
|
150
|
+
return `## How to run this in Dreamstate\n\n${routerStepLines()}\n\n${agentGuidance_generated_json_1.default.consent.summary}\n\nGoals: ${packs.length ? packs.join(', ') : 'not declared'}.`;
|
|
114
151
|
}
|
|
115
152
|
function packs(frontmatter) {
|
|
116
153
|
const value = frontmatter.packs;
|
|
@@ -129,20 +166,41 @@ function renderSkillMarkdown(skill, provenance) {
|
|
|
129
166
|
const lines = Object.entries(frontmatter).flatMap(([key, value]) => Array.isArray(value)
|
|
130
167
|
? [`${key}: [${value.map(yamlValue).join(', ')}]`]
|
|
131
168
|
: [`${key}: ${yamlValue(value)}`]);
|
|
132
|
-
return `---\n${lines.join('\n')}\n---\n\n${commandGuide(packs(frontmatter))}\n\n${skill.body.trim()}\n\n<!-- dreamstate provenance: workspace=${provenance.workspaceId} issued=${new Date().toISOString()} skills=${provenance.indexVersion} -->\n`;
|
|
169
|
+
return `---\n${lines.join('\n')}\n---\n\n${commandGuide(packs(frontmatter))}\n\n${skill.body.trim()}\n\n<!-- dreamstate provenance: workspace=${provenance.workspaceId} issued=${new Date().toISOString()} skills=${provenance.indexVersion} content=${skillContentHash(skill)} -->\n`;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* A supporting page's path under its skill directory, or null when it is not a plain
|
|
173
|
+
* relative path of safe segments. A remote name becomes a path, so traversal and
|
|
174
|
+
* absolute paths are refused here rather than trusted.
|
|
175
|
+
*/
|
|
176
|
+
function supportingFilePath(directory, name) {
|
|
177
|
+
if (!name || name.startsWith('/') || name.includes('\\') || name.includes('\0'))
|
|
178
|
+
return null;
|
|
179
|
+
const segments = (0, node_path_1.normalize)(name).split(node_path_1.sep);
|
|
180
|
+
if (segments.some((segment) => !segment || segment === '..' || segment === '.' || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(segment)))
|
|
181
|
+
return null;
|
|
182
|
+
if (segments.join('/') === 'SKILL.md')
|
|
183
|
+
return null;
|
|
184
|
+
return (0, node_path_1.join)(directory, ...segments);
|
|
133
185
|
}
|
|
134
186
|
function hash(value) { return (0, node_crypto_1.createHash)('sha256').update(value).digest('hex'); }
|
|
135
187
|
async function writeHostedSkill(root, skill, provenance) {
|
|
136
188
|
const name = skillName(skill.id);
|
|
137
189
|
const directory = (0, node_path_1.join)(root, name);
|
|
138
190
|
const markdown = renderSkillMarkdown(skill, provenance);
|
|
191
|
+
// A page removed upstream must not linger: clear a directory this CLI wrote before rewriting it.
|
|
192
|
+
if ((await (0, promises_1.readFile)((0, node_path_1.join)(directory, 'SKILL.md'), 'utf8').catch(() => '')).includes(PROVENANCE_MARKER)) {
|
|
193
|
+
await (0, promises_1.rm)(directory, { recursive: true, force: true });
|
|
194
|
+
}
|
|
139
195
|
await (0, promises_1.mkdir)(directory, { recursive: true, mode: 0o700 });
|
|
140
196
|
const file = (0, node_path_1.join)(directory, 'SKILL.md');
|
|
141
197
|
await (0, promises_1.writeFile)(file, markdown, { encoding: 'utf8', mode: 0o600 });
|
|
142
198
|
for (const document of skill.documents ?? []) {
|
|
143
|
-
|
|
199
|
+
const target = supportingFilePath(directory, document.name);
|
|
200
|
+
if (!target)
|
|
144
201
|
continue;
|
|
145
|
-
await (0, promises_1.
|
|
202
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(target), { recursive: true, mode: 0o700 });
|
|
203
|
+
await (0, promises_1.writeFile)(target, document.content, { encoding: 'utf8', mode: 0o600 });
|
|
146
204
|
}
|
|
147
205
|
return { file, name, computedHash: hash(markdown) };
|
|
148
206
|
}
|
|
@@ -151,8 +209,9 @@ async function linkAgentSkill(agentRoot, canonicalDirectory, name, copy) {
|
|
|
151
209
|
await (0, promises_1.mkdir)(agentRoot, { recursive: true, mode: 0o700 });
|
|
152
210
|
await (0, promises_1.rm)(targetDirectory, { recursive: true, force: true });
|
|
153
211
|
if (copy) {
|
|
154
|
-
|
|
155
|
-
|
|
212
|
+
// The whole skill directory, not only SKILL.md: the supporting pages the skill body
|
|
213
|
+
// links to must travel with it, or a copied skill points at files that are not there.
|
|
214
|
+
await (0, promises_1.cp)((0, node_path_1.join)(canonicalDirectory, name), targetDirectory, { recursive: true });
|
|
156
215
|
}
|
|
157
216
|
else {
|
|
158
217
|
await (0, promises_1.symlink)((0, node_path_1.relative)(agentRoot, (0, node_path_1.join)(canonicalDirectory, name)), targetDirectory, 'dir');
|
|
@@ -185,7 +244,7 @@ function routerSkill(packsList) {
|
|
|
185
244
|
const goals = records.map((item) => item && typeof item === 'object' ? item : {})
|
|
186
245
|
.filter((item) => typeof item.id === 'string');
|
|
187
246
|
const lines = goals.map((pack) => `- ${pack.id}: ${pack.owns ?? 'Dreamstate capability pack.'}${pack.not_for ? ` ${pack.not_for}` : ''}`).join('\n');
|
|
188
|
-
return { id: 'router', name: 'Dreamstate', description: 'Route work to Dreamstate capability skills.', body: `# Dreamstate router\n\nPrefer narrower \`dreamstate-*\` skill when one fits. Otherwise
|
|
247
|
+
return { id: 'router', name: 'Dreamstate', description: 'Route work to Dreamstate capability skills.', body: `# Dreamstate router\n\nPrefer a narrower \`dreamstate-*\` skill when one fits. Otherwise:\n\n${routerStepLines()}\n\n## Paid and outward-facing runs\n\n${agentGuidance_generated_json_1.default.consent.paid_run}\n\n${agentGuidance_generated_json_1.default.consent.human_approval}\n\n## Goals\n\n${lines || 'No packs returned by GET /packs.'}`, frontmatter: { packs: goals.map((pack) => pack.id) } };
|
|
189
248
|
}
|
|
190
249
|
async function inspectSkillInstallers(agents, homeDirectory = (0, node_os_1.homedir)(), project = false, cwd = process.cwd()) {
|
|
191
250
|
const canonical = canonicalSkillsDirectory(homeDirectory, project, cwd);
|
|
@@ -234,3 +293,43 @@ async function inspectSkillInstallers(agents, homeDirectory = (0, node_os_1.home
|
|
|
234
293
|
return { agent, directory, writable, canonical_directory: canonical, symlinks, provenance_age_ms };
|
|
235
294
|
}));
|
|
236
295
|
}
|
|
296
|
+
const PROVENANCE_PATTERN = /<!-- dreamstate provenance: workspace=[^\s]+ issued=[^\s]+ skills=[^\s]+(?: content=([0-9a-f]+))? -->/;
|
|
297
|
+
/**
|
|
298
|
+
* Compares what is installed with the live skills, by content stamp and not by age.
|
|
299
|
+
* An install an hour old that predates a server-side edit is stale; one from last
|
|
300
|
+
* month that nothing has changed since is current.
|
|
301
|
+
*/
|
|
302
|
+
async function compareInstalledSkills(live, homeDirectory = (0, node_os_1.homedir)(), project = false, cwd = process.cwd()) {
|
|
303
|
+
const canonical = canonicalSkillsDirectory(homeDirectory, project, cwd);
|
|
304
|
+
let names = [];
|
|
305
|
+
try {
|
|
306
|
+
names = (await (0, promises_1.readdir)(canonical)).filter((name) => name === 'dreamstate' || name.startsWith('dreamstate-'));
|
|
307
|
+
}
|
|
308
|
+
catch { /* nothing installed */ }
|
|
309
|
+
const installedStamps = new Map();
|
|
310
|
+
for (const name of names) {
|
|
311
|
+
const id = name === 'dreamstate' ? 'router' : name.slice('dreamstate-'.length);
|
|
312
|
+
try {
|
|
313
|
+
const markdown = await (0, promises_1.readFile)((0, node_path_1.join)(canonical, name, 'SKILL.md'), 'utf8');
|
|
314
|
+
installedStamps.set(id, PROVENANCE_PATTERN.exec(markdown)?.[1] ?? null);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
installedStamps.set(id, null);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const liveIds = live.map((skill) => skill.id);
|
|
321
|
+
const missing = liveIds.filter((id) => !installedStamps.has(id));
|
|
322
|
+
const extra = [...installedStamps.keys()].filter((id) => !liveIds.includes(id)).sort();
|
|
323
|
+
const stale = live
|
|
324
|
+
.filter((skill) => installedStamps.has(skill.id) && installedStamps.get(skill.id) !== skillContentHash(skill))
|
|
325
|
+
.map((skill) => ({ id: skill.id, installed: installedStamps.get(skill.id) ?? null, live: skillContentHash(skill) }));
|
|
326
|
+
return {
|
|
327
|
+
installed_skill_ids: [...installedStamps.keys()].sort(),
|
|
328
|
+
live_skill_ids: liveIds,
|
|
329
|
+
missing,
|
|
330
|
+
extra,
|
|
331
|
+
stale,
|
|
332
|
+
in_sync: missing.length === 0 && extra.length === 0 && stale.length === 0,
|
|
333
|
+
refresh_command: `dreamstate skills install${project ? ' --project' : ''}`,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
@@ -8,5 +8,19 @@ export interface LocalTableFilePreview {
|
|
|
8
8
|
writes: false;
|
|
9
9
|
}
|
|
10
10
|
export declare function inferLocalTableFileKind(filePath: string, format?: string): LocalTableFileKind;
|
|
11
|
+
export declare function parseCsv(text: string): {
|
|
12
|
+
rows: string[][];
|
|
13
|
+
endedClean: boolean;
|
|
14
|
+
unterminatedQuote: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The first worksheet of an xlsx file as rows of cell text. `rowLimit` stops at
|
|
18
|
+
* that many rows (the preview needs a header and a sample); null reads them all
|
|
19
|
+
* (an import needs every row).
|
|
20
|
+
*/
|
|
21
|
+
export declare function readXlsxRows(buffer: Buffer, rowLimit: number | null): {
|
|
22
|
+
rows: string[][];
|
|
23
|
+
totalRows: number;
|
|
24
|
+
};
|
|
11
25
|
export declare function previewLocalTableFile(filePath: string, format?: string): Promise<LocalTableFilePreview>;
|
|
12
26
|
//# sourceMappingURL=tableFilePreview.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableFilePreview.d.ts","sourceRoot":"","sources":["../src/tableFilePreview.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;CACf;AAgBD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAK7F;
|
|
1
|
+
{"version":3,"file":"tableFilePreview.d.ts","sourceRoot":"","sources":["../src/tableFilePreview.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;CACf;AAgBD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAK7F;AAyBD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAwC5G;AA0HD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAsC7G;AAQD,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAgB7G"}
|