@skrr-ai/cli 0.1.42 → 0.1.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-command.d.ts +2 -0
- package/dist/base-command.js +1 -0
- package/dist/commands/balance/index.js +1 -1
- package/dist/commands/balance/overage.js +4 -3
- package/dist/commands/balance/plan.js +10 -6
- package/dist/commands/balance/show.d.ts +32 -0
- package/dist/commands/balance/show.js +74 -3
- package/dist/commands/balance/usage/events.js +3 -2
- package/dist/commands/balance/usage.js +2 -1
- package/dist/commands/browser/install.js +3 -2
- package/dist/commands/browser/uninstall.js +3 -2
- package/dist/commands/code/handover.d.ts +1 -0
- package/dist/commands/code/handover.js +4 -0
- package/dist/commands/code/install.js +3 -2
- package/dist/commands/code/jobs/run.d.ts +1 -0
- package/dist/commands/code/jobs/run.js +4 -0
- package/dist/commands/daemon/install.js +7 -0
- package/dist/commands/harnesses/install.d.ts +11 -0
- package/dist/commands/harnesses/install.js +33 -14
- package/dist/commands/harnesses/installers.d.ts +10 -0
- package/dist/commands/harnesses/installers.js +31 -0
- package/dist/commands/harnesses/leases/show.js +14 -0
- package/dist/commands/harnesses/list.js +3 -2
- package/dist/commands/instructions/install.d.ts +22 -0
- package/dist/commands/instructions/install.js +83 -7
- package/dist/commands/instructions/list.js +5 -0
- package/dist/commands/instructions/show.d.ts +6 -0
- package/dist/commands/instructions/show.js +34 -1
- package/dist/commands/instructions/status.js +17 -1
- package/dist/commands/payments/wallet.js +2 -2
- package/dist/commands/tasks/attachments/set-role.d.ts +24 -0
- package/dist/commands/tasks/attachments/set-role.js +60 -0
- package/dist/commands/tasks/attachments/upload.d.ts +1 -0
- package/dist/commands/tasks/attachments/upload.js +18 -52
- package/dist/commands/tasks/comments/add.d.ts +1 -0
- package/dist/commands/tasks/comments/add.js +67 -2
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +56 -1
- package/dist/commands/tasks/create.d.ts +6 -0
- package/dist/commands/tasks/create.js +26 -3
- package/dist/commands/tasks/labels/attach.js +4 -0
- package/dist/commands/tasks/list.d.ts +1 -0
- package/dist/commands/tasks/list.js +9 -0
- package/dist/commands/tasks/result/submit.d.ts +3 -0
- package/dist/commands/tasks/result/submit.js +76 -8
- package/dist/commands/tasks/show.d.ts +23 -0
- package/dist/commands/tasks/show.js +61 -1
- package/dist/commands/tasks/update.js +16 -2
- package/dist/commands/tasks/updates/add.d.ts +1 -0
- package/dist/commands/tasks/updates/add.js +63 -0
- package/dist/commands/views/create.js +12 -2
- package/dist/commands/views/list.js +3 -2
- package/dist/commands/views/show.js +2 -0
- package/dist/lib/agentic-stream.d.ts +10 -4
- package/dist/lib/agentic-stream.js +25 -11
- package/dist/lib/api-fetch.js +7 -2
- package/dist/lib/cli-installers.d.ts +23 -4
- package/dist/lib/cli-installers.js +56 -8
- package/dist/lib/daemon-setup.d.ts +18 -1
- package/dist/lib/daemon-setup.js +33 -1
- package/dist/lib/dedicated-machines.js +4 -2
- package/dist/lib/file-mime.js +1 -1
- package/dist/lib/first-party-harness-agent.d.ts +16 -1
- package/dist/lib/first-party-harness-agent.js +47 -17
- package/dist/lib/first-party-harness-doctor.js +49 -48
- package/dist/lib/first-party-harness-managed.d.ts +9 -4
- package/dist/lib/first-party-harness-managed.js +13 -10
- package/dist/lib/first-party-harness.d.ts +32 -21
- package/dist/lib/first-party-harness.js +49 -31
- package/dist/lib/harness-provider-input.d.ts +18 -12
- package/dist/lib/harness-provider-input.js +18 -12
- package/dist/lib/harness-tiers.d.ts +4 -3
- package/dist/lib/harness-tiers.js +4 -3
- package/dist/lib/harnesses.d.ts +6 -0
- package/dist/lib/html-text.js +25 -0
- package/dist/lib/instruction-input.d.ts +21 -0
- package/dist/lib/instruction-input.js +30 -0
- package/dist/lib/instruction-provenance.d.ts +54 -0
- package/dist/lib/instruction-provenance.js +84 -0
- package/dist/lib/session-task-endpoints.d.ts +1 -1
- package/dist/lib/session-task-endpoints.js +3 -0
- package/dist/lib/task-asset-upload.d.ts +84 -0
- package/dist/lib/task-asset-upload.js +374 -0
- package/dist/lib/task-closure.d.ts +15 -0
- package/dist/lib/task-closure.js +20 -0
- package/dist/lib/task-view-render.d.ts +14 -0
- package/dist/lib/task-view-render.js +55 -0
- package/dist/lib/tasks.d.ts +26 -0
- package/dist/lib/tasks.js +38 -1
- package/dist/lib/views/vocabulary.d.ts +1 -1
- package/dist/lib/views/vocabulary.js +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +183 -58
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +286 -100
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +21 -33
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +24 -50
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.d.ts +19 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +26 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.d.ts +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +1 -13
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.d.ts +21 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/legacyStatePreflight.js +75 -19
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +183 -58
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +279 -99
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +21 -33
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +24 -49
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.d.ts +19 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +27 -11
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.d.ts +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +9 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.d.ts +21 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/legacyStatePreflight.js +74 -19
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4588 -4509
- package/dist/node_modules/@skrr-ai/data-provider/package.json +1 -1
- package/oclif.manifest.json +33980 -33832
- package/package.json +3 -3
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readTaskForUpload = readTaskForUpload;
|
|
37
|
+
exports.uploadTaskAssetFile = uploadTaskAssetFile;
|
|
38
|
+
exports.attachTaskAssetFiles = attachTaskAssetFiles;
|
|
39
|
+
exports.taskAssetMarkdownRef = taskAssetMarkdownRef;
|
|
40
|
+
exports.sha256OfFile = sha256OfFile;
|
|
41
|
+
exports.postFileToStorage = postFileToStorage;
|
|
42
|
+
/**
|
|
43
|
+
* One Task-asset upload path for every CLI surface — `tasks attachments
|
|
44
|
+
* upload` and the `--attach` flag on updates/result/complete/comments all
|
|
45
|
+
* funnel here so the routing rules live in exactly one place (OSK-9863).
|
|
46
|
+
*
|
|
47
|
+
* ≤25MB or image → buffered multipart (canonicalization needs the bytes)
|
|
48
|
+
* larger non-image → intent → presigned POST to S3 → complete (OSK-9867)
|
|
49
|
+
*
|
|
50
|
+
* Session routing follows the CREDENTIAL, resolved here once per file so a
|
|
51
|
+
* narrowed agent session lands on `task-attachments*` and a human (or a
|
|
52
|
+
* delegated session holding a wide credential) lands on `/api/tasks/:id/*`.
|
|
53
|
+
*
|
|
54
|
+
* Retry safety is server-side: the sha256 IS the asset identity, so a second
|
|
55
|
+
* upload of the same bytes returns the existing ready row instead of
|
|
56
|
+
* duplicating it.
|
|
57
|
+
*
|
|
58
|
+
* The digest this module REPORTS is always the server's. The server
|
|
59
|
+
* canonicalizes images (EXIF strip, orientation, re-encode) before storing
|
|
60
|
+
* them, so the bytes on disk and the bytes stored are routinely different; an
|
|
61
|
+
* evidence reference that named the local hash would pin a version of the
|
|
62
|
+
* file that was never stored (OSK-10120). The local hash is computed only
|
|
63
|
+
* where the protocol needs it — declaring a direct upload, which storage then
|
|
64
|
+
* enforces — and never leaves this module as a claim about the asset.
|
|
65
|
+
*/
|
|
66
|
+
const fs = __importStar(require("node:fs"));
|
|
67
|
+
const http = __importStar(require("node:http"));
|
|
68
|
+
const https = __importStar(require("node:https"));
|
|
69
|
+
const path = __importStar(require("node:path"));
|
|
70
|
+
const node_buffer_1 = require("node:buffer");
|
|
71
|
+
const node_crypto_1 = require("node:crypto");
|
|
72
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
73
|
+
const base_command_1 = require("../base-command");
|
|
74
|
+
const file_mime_1 = require("./file-mime");
|
|
75
|
+
const api_fetch_1 = require("./api-fetch");
|
|
76
|
+
const session_task_endpoints_1 = require("./session-task-endpoints");
|
|
77
|
+
function mb(bytes) {
|
|
78
|
+
return `${Math.floor(bytes / (1024 * 1024))} MB`;
|
|
79
|
+
}
|
|
80
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/i;
|
|
81
|
+
function storedDigest(asset) {
|
|
82
|
+
const value = asset.contentSha256;
|
|
83
|
+
return typeof value === 'string' && SHA256_HEX.test(value) ? value.toLowerCase() : undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Read the Task an upload targets, through the same credential the upload
|
|
87
|
+
* will use. In a session the task comes from the claim, so the read is the
|
|
88
|
+
* bound task and `taskId` is only reconciled against it — a scoped credential
|
|
89
|
+
* refuses to act on any other task before a byte leaves the machine.
|
|
90
|
+
*/
|
|
91
|
+
async function readTaskForUpload(taskId) {
|
|
92
|
+
const readPath = await (0, session_task_endpoints_1.sessionScopedTaskPath)('read');
|
|
93
|
+
if (readPath) {
|
|
94
|
+
const bound = await (0, api_fetch_1.apiFetch)(readPath);
|
|
95
|
+
if (!(0, session_task_endpoints_1.requestMatchesBoundTask)(bound, taskId)) {
|
|
96
|
+
throw new Error(`This session is bound to task ${String(bound.identifier ?? bound.id ?? '?')} — a scoped credential cannot attach files to ${taskId}.`);
|
|
97
|
+
}
|
|
98
|
+
return bound;
|
|
99
|
+
}
|
|
100
|
+
return (await data_provider_1.dataService.getTask(taskId, { enrich: false }));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Upload `filePath` as a Task asset. In a session the task comes from the
|
|
104
|
+
* claim — `taskId` is only reconciled against the binding, never sent.
|
|
105
|
+
* Throws a plain Error; callers decide how to surface it.
|
|
106
|
+
*/
|
|
107
|
+
async function uploadTaskAssetFile(opts) {
|
|
108
|
+
const { taskId, filePath, role } = opts;
|
|
109
|
+
if (!fs.existsSync(filePath)) {
|
|
110
|
+
throw new Error(`File not found: ${filePath}`);
|
|
111
|
+
}
|
|
112
|
+
const stat = fs.statSync(filePath);
|
|
113
|
+
if (!stat.isFile()) {
|
|
114
|
+
throw new Error(`Not a regular file: ${filePath}`);
|
|
115
|
+
}
|
|
116
|
+
const size = stat.size;
|
|
117
|
+
const filename = path.basename(filePath);
|
|
118
|
+
const mimeType = (0, file_mime_1.mimeTypeForFilename)(filename);
|
|
119
|
+
const isImage = mimeType.startsWith('image/');
|
|
120
|
+
if (isImage && size > data_provider_1.TASK_ATTACHMENT_MAX_BYTES) {
|
|
121
|
+
throw new Error(`${filename} is too large for an image (max ${mb(data_provider_1.TASK_ATTACHMENT_MAX_BYTES)})`);
|
|
122
|
+
}
|
|
123
|
+
if (size > data_provider_1.TASK_DIRECT_UPLOAD_MAX_BYTES) {
|
|
124
|
+
throw new Error(`${filename} exceeds the direct-upload limit (${mb(data_provider_1.TASK_DIRECT_UPLOAD_MAX_BYTES)})`);
|
|
125
|
+
}
|
|
126
|
+
const direct = !isImage && size > data_provider_1.TASK_ATTACHMENT_MAX_BYTES;
|
|
127
|
+
const sessionPath = await (0, session_task_endpoints_1.sessionScopedTaskPath)('attachment');
|
|
128
|
+
let result;
|
|
129
|
+
try {
|
|
130
|
+
if (sessionPath) {
|
|
131
|
+
await readTaskForUpload(taskId);
|
|
132
|
+
result = direct
|
|
133
|
+
? await sessionDirectUpload({ filePath, size, filename, mimeType, role })
|
|
134
|
+
: await sessionBufferedUpload({ filePath, filename, mimeType, role });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
result = direct
|
|
138
|
+
? await genericDirectUpload({ taskId, filePath, size, filename, mimeType, role })
|
|
139
|
+
: await genericBufferedUpload({ taskId, filePath, filename, mimeType, role });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
throw withServerReason(err, filename);
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
id: String(result.id ?? result._id),
|
|
147
|
+
digest: storedDigest(result),
|
|
148
|
+
filename,
|
|
149
|
+
mimeType,
|
|
150
|
+
deduplicated: result.deduplicated === true,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Put the server's own reason on a refused upload.
|
|
155
|
+
*
|
|
156
|
+
* The transports keep response bodies out of `message` (a body can carry a
|
|
157
|
+
* stack trace), so a refusal read `HTTP 403 Forbidden — POST …` — and `--attach`
|
|
158
|
+
* prints only the message. Task media refusals are written to be acted on: 422
|
|
159
|
+
* an image whose bytes cannot be decoded, 415 a type the bytes contradict, 413
|
|
160
|
+
* the storage quota, 403 an agent asking for a Run input. The reason and its
|
|
161
|
+
* code replace the transport line; status and body stay on the error, so
|
|
162
|
+
* `handleApiError` still reads them. An error with no stated reason is left
|
|
163
|
+
* exactly as it was.
|
|
164
|
+
*/
|
|
165
|
+
function withServerReason(err, filename) {
|
|
166
|
+
if (!(err instanceof Error))
|
|
167
|
+
return err;
|
|
168
|
+
const { code, message } = (0, base_command_1.apiRefusal)(err);
|
|
169
|
+
if (!message)
|
|
170
|
+
return err;
|
|
171
|
+
err.message = `${filename}: ${message}${code ? ` (${code})` : ''}`;
|
|
172
|
+
return err;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Upload every `--attach` file and return the reference objects an Update or
|
|
176
|
+
* Result appends to `evidenceRefs`. Serial: half a dozen files is the
|
|
177
|
+
* realistic case and parallel uploads would race the session rate limiter.
|
|
178
|
+
*/
|
|
179
|
+
async function attachTaskAssetFiles(opts) {
|
|
180
|
+
const refs = [];
|
|
181
|
+
for (const filePath of opts.files) {
|
|
182
|
+
const asset = await uploadTaskAssetFile({
|
|
183
|
+
taskId: opts.taskId,
|
|
184
|
+
filePath,
|
|
185
|
+
role: opts.role,
|
|
186
|
+
});
|
|
187
|
+
refs.push({
|
|
188
|
+
kind: 'task_attachment',
|
|
189
|
+
id: asset.id,
|
|
190
|
+
...(asset.digest ? { digest: `sha256:${asset.digest}` } : {}),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return refs;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The markdown image a comment body carries for an asset. The alt text is the
|
|
197
|
+
* filename, so its brackets are escaped: `shot [final].png` would otherwise
|
|
198
|
+
* close the alt early and break the reference.
|
|
199
|
+
*/
|
|
200
|
+
function taskAssetMarkdownRef(asset) {
|
|
201
|
+
const alt = asset.filename.replace(/[\\[\]]/g, (ch) => `\\${ch}`);
|
|
202
|
+
return ``;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The buffered path holds the file in memory by design: it is capped at the
|
|
206
|
+
* buffered limit, and the server needs the whole body to canonicalize it.
|
|
207
|
+
*/
|
|
208
|
+
function fileFormData(filePath, filename, mimeType, role) {
|
|
209
|
+
const fd = new FormData();
|
|
210
|
+
fd.append('file', new node_buffer_1.Blob([fs.readFileSync(filePath)], { type: mimeType }), filename);
|
|
211
|
+
if (role)
|
|
212
|
+
fd.append('role', role);
|
|
213
|
+
return fd;
|
|
214
|
+
}
|
|
215
|
+
async function genericBufferedUpload(p) {
|
|
216
|
+
return data_provider_1.dataService.uploadTaskAttachment({
|
|
217
|
+
taskId: p.taskId,
|
|
218
|
+
formData: fileFormData(p.filePath, p.filename, p.mimeType, p.role),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
async function sessionBufferedUpload(p) {
|
|
222
|
+
return (0, api_fetch_1.apiFetch)((await (0, session_task_endpoints_1.sessionScopedTaskPath)('attachment')), {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
body: fileFormData(p.filePath, p.filename, p.mimeType, p.role),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
async function genericDirectUpload(p) {
|
|
228
|
+
const intent = await data_provider_1.dataService.createTaskAttachmentUploadIntent({
|
|
229
|
+
taskId: p.taskId,
|
|
230
|
+
filename: p.filename,
|
|
231
|
+
mimeType: p.mimeType,
|
|
232
|
+
sizeBytes: p.size,
|
|
233
|
+
sha256: await sha256OfFile(p.filePath),
|
|
234
|
+
role: p.role,
|
|
235
|
+
});
|
|
236
|
+
if (!intent.uploadUrl)
|
|
237
|
+
return intent.attachment;
|
|
238
|
+
await postFileToStorage({
|
|
239
|
+
uploadUrl: intent.uploadUrl,
|
|
240
|
+
uploadFields: intent.uploadFields ?? {},
|
|
241
|
+
filePath: p.filePath,
|
|
242
|
+
size: p.size,
|
|
243
|
+
filename: p.filename,
|
|
244
|
+
mimeType: p.mimeType,
|
|
245
|
+
});
|
|
246
|
+
return data_provider_1.dataService.completeTaskAttachmentUpload({
|
|
247
|
+
taskId: p.taskId,
|
|
248
|
+
attachmentId: intent.attachment.id,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async function sessionDirectUpload(p) {
|
|
252
|
+
const intent = await (0, api_fetch_1.apiFetch)((await (0, session_task_endpoints_1.sessionScopedTaskPath)('attachmentIntent')), {
|
|
253
|
+
method: 'POST',
|
|
254
|
+
body: {
|
|
255
|
+
filename: p.filename,
|
|
256
|
+
mimeType: p.mimeType,
|
|
257
|
+
sizeBytes: p.size,
|
|
258
|
+
sha256: await sha256OfFile(p.filePath),
|
|
259
|
+
...(p.role ? { role: p.role } : {}),
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
if (!intent.uploadUrl)
|
|
263
|
+
return intent.attachment;
|
|
264
|
+
await postFileToStorage({
|
|
265
|
+
uploadUrl: intent.uploadUrl,
|
|
266
|
+
uploadFields: intent.uploadFields ?? {},
|
|
267
|
+
filePath: p.filePath,
|
|
268
|
+
size: p.size,
|
|
269
|
+
filename: p.filename,
|
|
270
|
+
mimeType: p.mimeType,
|
|
271
|
+
});
|
|
272
|
+
return (0, api_fetch_1.apiFetch)((await (0, session_task_endpoints_1.sessionScopedTaskPath)('attachmentComplete')), {
|
|
273
|
+
method: 'POST',
|
|
274
|
+
body: { attachmentId: intent.attachment.id },
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/** sha256 of a file, read as a stream: a 250MB recording never sits in memory. */
|
|
278
|
+
async function sha256OfFile(filePath) {
|
|
279
|
+
const hash = (0, node_crypto_1.createHash)('sha256');
|
|
280
|
+
for await (const chunk of fs.createReadStream(filePath)) {
|
|
281
|
+
hash.update(chunk);
|
|
282
|
+
}
|
|
283
|
+
return hash.digest('hex');
|
|
284
|
+
}
|
|
285
|
+
/** A form-data header value: no CR/LF, and quotes percent-encoded. */
|
|
286
|
+
function quotedHeaderValue(value) {
|
|
287
|
+
return value.replace(/[\r\n]/g, ' ').replace(/"/g, '%22');
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* POST the file to the presigned URL as multipart/form-data, streamed from
|
|
291
|
+
* disk.
|
|
292
|
+
*
|
|
293
|
+
* Built by hand rather than with `FormData` + `fetch` for two reasons, both
|
|
294
|
+
* about large files. `FormData` needs a `Blob`, which here means the whole
|
|
295
|
+
* file in memory — the double buffering this replaced read up to 250MB and
|
|
296
|
+
* then copied it again. And storage refuses a POST without a Content-Length
|
|
297
|
+
* (it does not take chunked uploads), which a streamed `fetch` body cannot
|
|
298
|
+
* promise; the exact length is known here, because every part except the file
|
|
299
|
+
* is a small in-memory string and the file's size came from `stat`.
|
|
300
|
+
*
|
|
301
|
+
* `file` goes LAST — S3 presigned POST evaluates fields in order and ignores
|
|
302
|
+
* anything after it. The fields carry `x-amz-checksum-sha256`, so storage
|
|
303
|
+
* itself rejects bytes that do not match the digest the intent declared,
|
|
304
|
+
* including a file that changed between hashing and upload.
|
|
305
|
+
*/
|
|
306
|
+
async function postFileToStorage(p) {
|
|
307
|
+
const boundary = `----skrr-upload-${(0, node_crypto_1.randomBytes)(16).toString('hex')}`;
|
|
308
|
+
const fieldParts = Object.entries(p.uploadFields).map(([name, value]) => `--${boundary}\r\nContent-Disposition: form-data; name="${quotedHeaderValue(name)}"\r\n\r\n${value}\r\n`);
|
|
309
|
+
const head = Buffer.from(fieldParts.join('') +
|
|
310
|
+
`--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="${quotedHeaderValue(p.filename)}"\r\nContent-Type: ${quotedHeaderValue(p.mimeType)}\r\n\r\n`, 'utf8');
|
|
311
|
+
const tail = Buffer.from(`\r\n--${boundary}--\r\n`, 'utf8');
|
|
312
|
+
const url = new URL(p.uploadUrl);
|
|
313
|
+
const transport = url.protocol === 'http:' ? http : https;
|
|
314
|
+
await new Promise((resolve, reject) => {
|
|
315
|
+
let settled = false;
|
|
316
|
+
const fail = (err) => {
|
|
317
|
+
if (settled)
|
|
318
|
+
return;
|
|
319
|
+
settled = true;
|
|
320
|
+
reject(err);
|
|
321
|
+
};
|
|
322
|
+
const req = transport.request(url, {
|
|
323
|
+
method: 'POST',
|
|
324
|
+
headers: {
|
|
325
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
326
|
+
'Content-Length': String(head.length + p.size + tail.length),
|
|
327
|
+
},
|
|
328
|
+
}, (res) => {
|
|
329
|
+
let body = '';
|
|
330
|
+
res.setEncoding('utf8');
|
|
331
|
+
res.on('data', (chunk) => {
|
|
332
|
+
if (body.length < 4096)
|
|
333
|
+
body += chunk;
|
|
334
|
+
});
|
|
335
|
+
res.on('error', fail);
|
|
336
|
+
res.on('end', () => {
|
|
337
|
+
const status = res.statusCode ?? 0;
|
|
338
|
+
if (status >= 200 && status < 300) {
|
|
339
|
+
if (!settled) {
|
|
340
|
+
settled = true;
|
|
341
|
+
resolve();
|
|
342
|
+
}
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// S3 names the refusal in XML (`<Code>BadDigest</Code>`,
|
|
346
|
+
// `EntityTooLarge`, `AccessDenied` once the POST policy expired).
|
|
347
|
+
// The code is the only part a person can act on.
|
|
348
|
+
const code = /<Code>([^<]+)<\/Code>/.exec(body)?.[1];
|
|
349
|
+
fail(new Error(`Storage rejected the upload (${status}${code ? ` ${code}` : ''})`));
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
req.on('error', fail);
|
|
353
|
+
req.write(head);
|
|
354
|
+
let sent = 0;
|
|
355
|
+
const stream = fs.createReadStream(p.filePath);
|
|
356
|
+
stream.on('data', (chunk) => {
|
|
357
|
+
sent += chunk.length;
|
|
358
|
+
});
|
|
359
|
+
stream.on('error', (err) => {
|
|
360
|
+
req.destroy(err);
|
|
361
|
+
fail(err);
|
|
362
|
+
});
|
|
363
|
+
stream.on('end', () => {
|
|
364
|
+
if (sent !== p.size) {
|
|
365
|
+
const err = new Error(`${p.filename} changed while it was being uploaded`);
|
|
366
|
+
req.destroy(err);
|
|
367
|
+
fail(err);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
req.end(tail);
|
|
371
|
+
});
|
|
372
|
+
stream.pipe(req, { end: false });
|
|
373
|
+
});
|
|
374
|
+
}
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import type { TaskClosureEvaluation } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* Is this Task SETTLED — closed in a way that refuses a new Result until it is
|
|
4
|
+
* reopened (`TASK_REOPEN_REQUIRED`)?
|
|
5
|
+
*
|
|
6
|
+
* Read the same way the server reads it: the immutable `statusType` when the row
|
|
7
|
+
* carries a known one, the legacy status id otherwise, and the `settled` band
|
|
8
|
+
* from the shared vocabulary rather than a column name. A command asks this
|
|
9
|
+
* BEFORE doing something the refusal would strand — uploading `--attach` files
|
|
10
|
+
* for a Result the server is about to refuse — and never instead of the
|
|
11
|
+
* server's own check, which stays the authority.
|
|
12
|
+
*/
|
|
13
|
+
export declare function taskIsSettled(task: {
|
|
14
|
+
statusType?: unknown;
|
|
15
|
+
status?: unknown;
|
|
16
|
+
} | null | undefined): boolean;
|
|
2
17
|
/**
|
|
3
18
|
* Render "where does this Task actually stand" for every surface that should
|
|
4
19
|
* say it.
|
package/dist/lib/task-closure.js
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.closureSnapshotLines = exports.describeAssessor = void 0;
|
|
4
|
+
exports.taskIsSettled = taskIsSettled;
|
|
4
5
|
exports.closureReport = closureReport;
|
|
5
6
|
exports.reopenRequiredLines = reopenRequiredLines;
|
|
6
7
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
8
|
+
/**
|
|
9
|
+
* Is this Task SETTLED — closed in a way that refuses a new Result until it is
|
|
10
|
+
* reopened (`TASK_REOPEN_REQUIRED`)?
|
|
11
|
+
*
|
|
12
|
+
* Read the same way the server reads it: the immutable `statusType` when the row
|
|
13
|
+
* carries a known one, the legacy status id otherwise, and the `settled` band
|
|
14
|
+
* from the shared vocabulary rather than a column name. A command asks this
|
|
15
|
+
* BEFORE doing something the refusal would strand — uploading `--attach` files
|
|
16
|
+
* for a Result the server is about to refuse — and never instead of the
|
|
17
|
+
* server's own check, which stays the authority.
|
|
18
|
+
*/
|
|
19
|
+
function taskIsSettled(task) {
|
|
20
|
+
if (!task)
|
|
21
|
+
return false;
|
|
22
|
+
const type = (0, data_provider_1.isTaskWorkflowStateType)(task.statusType)
|
|
23
|
+
? task.statusType
|
|
24
|
+
: data_provider_1.LEGACY_STATUS_TYPE_BY_ID[String(task.status ?? '')];
|
|
25
|
+
return Boolean(type) && data_provider_1.TASK_WORKFLOW_TYPE_BANDS.settled.includes(type);
|
|
26
|
+
}
|
|
7
27
|
function isUnavailable(closure) {
|
|
8
28
|
return Boolean(closure && closure.unavailable);
|
|
9
29
|
}
|
|
@@ -13,12 +13,15 @@
|
|
|
13
13
|
* go.
|
|
14
14
|
*/
|
|
15
15
|
export interface TaskViewFilters {
|
|
16
|
+
quickFilter?: string;
|
|
16
17
|
statuses?: string[];
|
|
18
|
+
statusTypes?: string[];
|
|
17
19
|
priorities?: string[];
|
|
18
20
|
assignees?: string[];
|
|
19
21
|
labels?: string[];
|
|
20
22
|
goalIds?: string[];
|
|
21
23
|
projectIds?: string[];
|
|
24
|
+
cycleIds?: string[];
|
|
22
25
|
search?: string;
|
|
23
26
|
}
|
|
24
27
|
export interface TaskViewLike {
|
|
@@ -69,3 +72,14 @@ export declare function immutableViewPatchKeys(body: Record<string, unknown>): s
|
|
|
69
72
|
* than listing six empty ones.
|
|
70
73
|
*/
|
|
71
74
|
export declare function describeTaskView(view: TaskViewLike): string[];
|
|
75
|
+
/**
|
|
76
|
+
* One line saying what a view SELECTS, for a table cell.
|
|
77
|
+
*
|
|
78
|
+
* `views list` had a SELECTION column whose value was the word `criteria` for
|
|
79
|
+
* every view that was not a pinned task list — a kind label sitting where the
|
|
80
|
+
* reader looks for an answer (dogfood OSK-4646). Values that fit are named
|
|
81
|
+
* (statuses, priorities, the quick filter, the search); ids are counted, since
|
|
82
|
+
* a row of UUIDs answers nothing at a glance and `views show` prints them in
|
|
83
|
+
* full.
|
|
84
|
+
*/
|
|
85
|
+
export declare function summarizeTaskViewSelection(view: TaskViewLike): string;
|
|
@@ -18,6 +18,12 @@ exports.EDITABLE_VIEW_PATCH_FIELDS = void 0;
|
|
|
18
18
|
exports.unshareableViewWarning = unshareableViewWarning;
|
|
19
19
|
exports.immutableViewPatchKeys = immutableViewPatchKeys;
|
|
20
20
|
exports.describeTaskView = describeTaskView;
|
|
21
|
+
exports.summarizeTaskViewSelection = summarizeTaskViewSelection;
|
|
22
|
+
/** `all` is the quick filter that filters nothing; any other one narrows. */
|
|
23
|
+
function narrowingQuickFilter(filters) {
|
|
24
|
+
const quick = filters.quickFilter;
|
|
25
|
+
return quick && quick !== 'all' ? quick : undefined;
|
|
26
|
+
}
|
|
21
27
|
/**
|
|
22
28
|
* OSK-4859 — a view created with no active workspace comes back with no
|
|
23
29
|
* `workspaceId`, and the server then refuses to share it
|
|
@@ -97,13 +103,20 @@ function describeTaskView(view) {
|
|
|
97
103
|
add('pinned tasks', `${pinned.length}: ${pinned.join(', ')}`);
|
|
98
104
|
}
|
|
99
105
|
const f = view.filters ?? {};
|
|
106
|
+
// Every selection field the create schema accepts. `--quick-filter` was a
|
|
107
|
+
// create flag this renderer never printed, so a saved quick filter was
|
|
108
|
+
// exactly the kind of selection that "did not take" invisibly.
|
|
109
|
+
const quick = narrowingQuickFilter(f);
|
|
100
110
|
const filterRows = [
|
|
111
|
+
['quick filter', quick ? [quick] : undefined],
|
|
101
112
|
['statuses', f.statuses],
|
|
113
|
+
['status types', f.statusTypes],
|
|
102
114
|
['priorities', f.priorities],
|
|
103
115
|
['assignees', f.assignees],
|
|
104
116
|
['labels', f.labels],
|
|
105
117
|
['goals', f.goalIds],
|
|
106
118
|
['projects', f.projectIds],
|
|
119
|
+
['cycles', f.cycleIds],
|
|
107
120
|
];
|
|
108
121
|
let anyFilter = false;
|
|
109
122
|
for (const [label, values] of filterRows) {
|
|
@@ -123,3 +136,45 @@ function describeTaskView(view) {
|
|
|
123
136
|
add('sort', describeShape(view.sort));
|
|
124
137
|
return lines;
|
|
125
138
|
}
|
|
139
|
+
const counted = (count, singular, plural = `${singular}s`) => `${count} ${count === 1 ? singular : plural}`;
|
|
140
|
+
/**
|
|
141
|
+
* One line saying what a view SELECTS, for a table cell.
|
|
142
|
+
*
|
|
143
|
+
* `views list` had a SELECTION column whose value was the word `criteria` for
|
|
144
|
+
* every view that was not a pinned task list — a kind label sitting where the
|
|
145
|
+
* reader looks for an answer (dogfood OSK-4646). Values that fit are named
|
|
146
|
+
* (statuses, priorities, the quick filter, the search); ids are counted, since
|
|
147
|
+
* a row of UUIDs answers nothing at a glance and `views show` prints them in
|
|
148
|
+
* full.
|
|
149
|
+
*/
|
|
150
|
+
function summarizeTaskViewSelection(view) {
|
|
151
|
+
const parts = [];
|
|
152
|
+
const pinned = view.taskIds ?? [];
|
|
153
|
+
if (pinned.length)
|
|
154
|
+
parts.push(counted(pinned.length, 'pinned task'));
|
|
155
|
+
const spaces = view.spaceIds ?? [];
|
|
156
|
+
parts.push(spaces.length ? counted(spaces.length, 'space') : 'all spaces');
|
|
157
|
+
const f = view.filters ?? {};
|
|
158
|
+
const quick = narrowingQuickFilter(f);
|
|
159
|
+
if (quick)
|
|
160
|
+
parts.push(quick);
|
|
161
|
+
if (f.statuses?.length)
|
|
162
|
+
parts.push(`status ${f.statuses.join('/')}`);
|
|
163
|
+
if (f.statusTypes?.length)
|
|
164
|
+
parts.push(`status type ${f.statusTypes.join('/')}`);
|
|
165
|
+
if (f.priorities?.length)
|
|
166
|
+
parts.push(`priority ${f.priorities.join('/')}`);
|
|
167
|
+
if (f.assignees?.length)
|
|
168
|
+
parts.push(counted(f.assignees.length, 'assignee'));
|
|
169
|
+
if (f.labels?.length)
|
|
170
|
+
parts.push(counted(f.labels.length, 'label'));
|
|
171
|
+
if (f.goalIds?.length)
|
|
172
|
+
parts.push(counted(f.goalIds.length, 'goal'));
|
|
173
|
+
if (f.projectIds?.length)
|
|
174
|
+
parts.push(counted(f.projectIds.length, 'project'));
|
|
175
|
+
if (f.cycleIds?.length)
|
|
176
|
+
parts.push(counted(f.cycleIds.length, 'cycle'));
|
|
177
|
+
if (f.search)
|
|
178
|
+
parts.push(`"${f.search}"`);
|
|
179
|
+
return parts.join(', ');
|
|
180
|
+
}
|
package/dist/lib/tasks.d.ts
CHANGED
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
import type { ParsedDeliverableCoordinate, ParsedExpectationSpec } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* `--goal` on `tasks update`. `none`, `null` and `clear` detach the goal: PATCH
|
|
4
|
+
* sends `goalId: null`. Anything else names a goal. `clear` is accepted because
|
|
5
|
+
* this same command documents it for `--expect`, so it is the spelling a user
|
|
6
|
+
* reaches for — and it used to be stored as a goal id (OSK-10207).
|
|
7
|
+
* Undefined means the flag was not passed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveTaskGoalFlag(value: string | undefined): string | null | undefined;
|
|
10
|
+
export declare const TASK_GOAL_NOT_FOUND = "TASK_GOAL_NOT_FOUND";
|
|
11
|
+
/**
|
|
12
|
+
* The refusal for a goal id that names no goal, in CLI terms.
|
|
13
|
+
*
|
|
14
|
+
* The server's sentence carries the API's remedy — "detach the goal with
|
|
15
|
+
* goalId: null" on update, "leave goalId out" on create — and a CLI user can
|
|
16
|
+
* type neither. So the goal id THIS command sent is named, with the flag that
|
|
17
|
+
* gets past the refusal: `--goal none` on update (see `resolveTaskGoalFlag`),
|
|
18
|
+
* leaving the goal out on create, where no goal is simply the default
|
|
19
|
+
* (OSK-10219). `goalSource: 'json'` is a create whose id came from
|
|
20
|
+
* `--from-json` rather than `--goal`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function describeTaskGoalNotFound({ goalId, command, bin, goalSource, }: {
|
|
23
|
+
goalId: string;
|
|
24
|
+
command: 'create' | 'update';
|
|
25
|
+
bin?: string;
|
|
26
|
+
goalSource?: 'flag' | 'json';
|
|
27
|
+
}): string;
|
|
2
28
|
export declare const TASK_PRIORITIES: readonly ["low", "medium", "high", "critical"];
|
|
3
29
|
/**
|
|
4
30
|
* The kinds `tasks events append --kind` will accept.
|
package/dist/lib/tasks.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RECOGNIZED_TASK_VERDICTS = exports.DELIVERABLE_LIFECYCLE_VALUES = exports.EXPECT_FLAG_HELP = exports.TASK_WORK_EVENT_KINDS = exports.TASK_PRIORITIES = void 0;
|
|
3
|
+
exports.RECOGNIZED_TASK_VERDICTS = exports.DELIVERABLE_LIFECYCLE_VALUES = exports.EXPECT_FLAG_HELP = exports.TASK_WORK_EVENT_KINDS = exports.TASK_PRIORITIES = exports.TASK_GOAL_NOT_FOUND = void 0;
|
|
4
|
+
exports.resolveTaskGoalFlag = resolveTaskGoalFlag;
|
|
5
|
+
exports.describeTaskGoalNotFound = describeTaskGoalNotFound;
|
|
4
6
|
exports.releasePinRepairGuard = releasePinRepairGuard;
|
|
5
7
|
exports.taskUpdateMutationGuard = taskUpdateMutationGuard;
|
|
6
8
|
exports.executionIsolationFromWorktreeFlag = executionIsolationFromWorktreeFlag;
|
|
@@ -36,6 +38,41 @@ exports.verdictIsRecognized = verdictIsRecognized;
|
|
|
36
38
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
37
39
|
const prompt_1 = require("./prompt");
|
|
38
40
|
const projects_1 = require("./projects");
|
|
41
|
+
/**
|
|
42
|
+
* `--goal` on `tasks update`. `none`, `null` and `clear` detach the goal: PATCH
|
|
43
|
+
* sends `goalId: null`. Anything else names a goal. `clear` is accepted because
|
|
44
|
+
* this same command documents it for `--expect`, so it is the spelling a user
|
|
45
|
+
* reaches for — and it used to be stored as a goal id (OSK-10207).
|
|
46
|
+
* Undefined means the flag was not passed.
|
|
47
|
+
*/
|
|
48
|
+
function resolveTaskGoalFlag(value) {
|
|
49
|
+
if (value === undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
const v = value.trim();
|
|
52
|
+
if (!v || ['none', 'null', 'clear'].includes(v.toLowerCase()))
|
|
53
|
+
return null;
|
|
54
|
+
return v;
|
|
55
|
+
}
|
|
56
|
+
exports.TASK_GOAL_NOT_FOUND = 'TASK_GOAL_NOT_FOUND';
|
|
57
|
+
/**
|
|
58
|
+
* The refusal for a goal id that names no goal, in CLI terms.
|
|
59
|
+
*
|
|
60
|
+
* The server's sentence carries the API's remedy — "detach the goal with
|
|
61
|
+
* goalId: null" on update, "leave goalId out" on create — and a CLI user can
|
|
62
|
+
* type neither. So the goal id THIS command sent is named, with the flag that
|
|
63
|
+
* gets past the refusal: `--goal none` on update (see `resolveTaskGoalFlag`),
|
|
64
|
+
* leaving the goal out on create, where no goal is simply the default
|
|
65
|
+
* (OSK-10219). `goalSource: 'json'` is a create whose id came from
|
|
66
|
+
* `--from-json` rather than `--goal`.
|
|
67
|
+
*/
|
|
68
|
+
function describeTaskGoalNotFound({ goalId, command, bin = 'skrr', goalSource = 'flag', }) {
|
|
69
|
+
const find = `Pass an existing goal id (\`${bin} goals list\` shows them)`;
|
|
70
|
+
if (command === 'update') {
|
|
71
|
+
return `No goal "${goalId}" exists. ${find}, or detach the task from its goal with \`--goal none\`.`;
|
|
72
|
+
}
|
|
73
|
+
const omit = goalSource === 'json' ? 'remove goalId from the --from-json body' : 'leave out --goal';
|
|
74
|
+
return `No goal "${goalId}" exists, so no task was created. ${find}, or ${omit} to create it without a goal.`;
|
|
75
|
+
}
|
|
39
76
|
exports.TASK_PRIORITIES = ['low', 'medium', 'high', 'critical'];
|
|
40
77
|
const DESCRIPTION_FORMATS = ['html', 'markdown', 'plain'];
|
|
41
78
|
/**
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* a re-export, not a second CLI vocabulary: adding a saved-view capability is
|
|
6
6
|
* one data-provider registration followed by renderer work on each surface.
|
|
7
7
|
*/
|
|
8
|
-
export { SPACE_RENDERABLE_VIEW_TYPES, TASK_RENDERABLE_VIEW_TYPES, VIEW_GROUP_BY_REGISTRY, VIEW_GROUP_BY_VALUES, VIEW_QUICK_FILTER_REGISTRY, VIEW_QUICK_FILTERS, VIEW_SORT_DIRECTIONS, VIEW_SORT_KEY_REGISTRY, VIEW_SORT_KEYS, VIEW_TYPE_REGISTRY, VIEW_TYPES, viewTypesForSurface, } from '@skrr-ai/data-provider';
|
|
8
|
+
export { SPACE_RENDERABLE_VIEW_TYPES, TASK_VIEW_DEFAULT_GROUP_BY, TASK_VIEW_DEFAULT_TYPE, TASK_RENDERABLE_VIEW_TYPES, VIEW_GROUP_BY_REGISTRY, VIEW_GROUP_BY_VALUES, VIEW_QUICK_FILTER_REGISTRY, VIEW_QUICK_FILTERS, VIEW_SORT_DIRECTIONS, VIEW_SORT_KEY_REGISTRY, VIEW_SORT_KEYS, VIEW_TYPE_REGISTRY, VIEW_TYPES, viewTypesForSurface, } from '@skrr-ai/data-provider';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY = exports.VIEW_SORT_KEYS = exports.VIEW_SORT_KEY_REGISTRY = exports.VIEW_SORT_DIRECTIONS = exports.VIEW_QUICK_FILTERS = exports.VIEW_QUICK_FILTER_REGISTRY = exports.VIEW_GROUP_BY_VALUES = exports.VIEW_GROUP_BY_REGISTRY = exports.TASK_RENDERABLE_VIEW_TYPES = exports.SPACE_RENDERABLE_VIEW_TYPES = void 0;
|
|
3
|
+
exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY = exports.VIEW_SORT_KEYS = exports.VIEW_SORT_KEY_REGISTRY = exports.VIEW_SORT_DIRECTIONS = exports.VIEW_QUICK_FILTERS = exports.VIEW_QUICK_FILTER_REGISTRY = exports.VIEW_GROUP_BY_VALUES = exports.VIEW_GROUP_BY_REGISTRY = exports.TASK_RENDERABLE_VIEW_TYPES = exports.TASK_VIEW_DEFAULT_TYPE = exports.TASK_VIEW_DEFAULT_GROUP_BY = exports.SPACE_RENDERABLE_VIEW_TYPES = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* CLI parity re-export for persisted task views.
|
|
6
6
|
*
|
|
@@ -10,6 +10,8 @@ exports.viewTypesForSurface = exports.VIEW_TYPES = exports.VIEW_TYPE_REGISTRY =
|
|
|
10
10
|
*/
|
|
11
11
|
var data_provider_1 = require("@skrr-ai/data-provider");
|
|
12
12
|
Object.defineProperty(exports, "SPACE_RENDERABLE_VIEW_TYPES", { enumerable: true, get: function () { return data_provider_1.SPACE_RENDERABLE_VIEW_TYPES; } });
|
|
13
|
+
Object.defineProperty(exports, "TASK_VIEW_DEFAULT_GROUP_BY", { enumerable: true, get: function () { return data_provider_1.TASK_VIEW_DEFAULT_GROUP_BY; } });
|
|
14
|
+
Object.defineProperty(exports, "TASK_VIEW_DEFAULT_TYPE", { enumerable: true, get: function () { return data_provider_1.TASK_VIEW_DEFAULT_TYPE; } });
|
|
13
15
|
Object.defineProperty(exports, "TASK_RENDERABLE_VIEW_TYPES", { enumerable: true, get: function () { return data_provider_1.TASK_RENDERABLE_VIEW_TYPES; } });
|
|
14
16
|
Object.defineProperty(exports, "VIEW_GROUP_BY_REGISTRY", { enumerable: true, get: function () { return data_provider_1.VIEW_GROUP_BY_REGISTRY; } });
|
|
15
17
|
Object.defineProperty(exports, "VIEW_GROUP_BY_VALUES", { enumerable: true, get: function () { return data_provider_1.VIEW_GROUP_BY_VALUES; } });
|