@aopslabs/aops 0.3.31 → 0.3.33
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 +11 -3
- package/aops-assets-release/aops-assets.json.gz +0 -0
- package/aops-assets-release/disciplines/build-review-chat/SKILL.md +33 -0
- package/aops-assets-release/disciplines/coordinator-loop/SKILL.md +33 -0
- package/aops-assets-release/disciplines/design-first-consensus/SKILL.md +30 -0
- package/aops-assets-release/disciplines/solo-pm-loop/SKILL.md +31 -0
- package/aops-assets-release/docs/user-guides/agentspace-user-guide.md +384 -0
- package/aops-assets-release/docs/user-guides/aops-cli-user-guide.md +2067 -0
- package/aops-assets-release/docs/user-guides/chatv3-user-guide.md +500 -0
- package/aops-assets-release/docs/user-guides/docman-user-guide.md +1009 -0
- package/aops-assets-release/docs/user-guides/projectman-user-guide.md +763 -0
- package/aops-assets-release/docs/user-guides/tasker-user-guide.md +244 -0
- package/aops-assets-release/release.json +6 -0
- package/aops-assets-release/roles/coordinator/ROLE.md +28 -0
- package/aops-assets-release/roles/implementer/ROLE.md +27 -0
- package/aops-assets-release/roles/reviewer/ROLE.md +27 -0
- package/aops-assets-release/skills/aops/SKILL.md +112 -0
- package/aops-assets-release/skills/aops-bootstrapper-authoring/SKILL.md +245 -0
- package/aops-assets-release/skills/aops-cli-agentspace/SKILL.md +186 -0
- package/aops-assets-release/skills/aops-cli-board-lifecycle/SKILL.md +64 -0
- package/aops-assets-release/skills/aops-cli-chat/SKILL.md +204 -0
- package/aops-assets-release/skills/aops-cli-collab/SKILL.md +42 -0
- package/aops-assets-release/skills/aops-cli-core/SKILL.md +219 -0
- package/aops-assets-release/skills/aops-cli-discuss/SKILL.md +172 -0
- package/aops-assets-release/skills/aops-cli-docman/SKILL.md +192 -0
- package/aops-assets-release/skills/aops-cli-fileman/SKILL.md +169 -0
- package/aops-assets-release/skills/aops-cli-mission/SKILL.md +128 -0
- package/aops-assets-release/skills/aops-cli-operator-brief/SKILL.md +67 -0
- package/aops-assets-release/skills/aops-cli-projectman/SKILL.md +235 -0
- package/aops-assets-release/skills/aops-cli-sugar-authoring/SKILL.md +188 -0
- package/aops-assets-release/skills/aops-cli-tasker/SKILL.md +108 -0
- package/aops-assets-release/skills/aops-cli-tooling-agent/SKILL.md +112 -0
- package/aops-assets-release/skills/aops-cli-view/SKILL.md +210 -0
- package/aops-assets-release/skills/aops-collaborative-work/SKILL.md +304 -0
- package/aops-assets-release/skills/aops-interactive/SKILL.md +70 -0
- package/aops-assets-release/skills/aops-loop-interactive/SKILL.md +314 -0
- package/aops-assets-release/skills/aops-working-disciplines/SKILL.md +310 -0
- package/aops-assets-release/skills/feature-retirement-flow/SKILL.md +126 -0
- package/assets/skills/aops-install/SKILL.md +18 -17
- package/dist/commands/assets.js +93 -1264
- package/dist/commands/community-server.js +27 -8
- package/dist/commands/community-setup.js +1 -2
- package/dist/commands/discuss.js +1 -1
- package/dist/commands/doc.js +88 -27
- package/dist/commands/docs.js +68 -0
- package/dist/commands/global-update.js +28 -0
- package/dist/commands/init.js +3 -1
- package/dist/commands/loop.js +6379 -0
- package/dist/commands/memory.js +2 -1
- package/dist/commands/pm/index.js +11 -9
- package/dist/commands/pm/projectman.js +33 -2
- package/dist/commands/project.js +6 -6
- package/dist/commands/prompt.js +1 -1
- package/dist/commands/repo-sync.js +92 -27
- package/dist/commands/runner.js +257 -0
- package/dist/commands/skill.js +1 -1
- package/dist/commands/start.js +1 -1
- package/dist/commands/tasker.js +361 -0
- package/dist/commands/view.js +53 -9
- package/dist/lib/commercial-setup-readiness-adapter.js +0 -1
- package/dist/lib/community-migration-snapshot.js +7 -9
- package/dist/lib/community-native-database-recovery.js +5 -14
- package/dist/lib/community-native-lifecycle.js +13 -0
- package/dist/lib/setup-agent-assets-bridge.js +28 -148
- package/dist/lib/setup-agent-assets-release.js +16 -44
- package/dist/lib/setup-init-orchestrator.js +11 -15
- package/dist/lib/simple-agent-assets.js +447 -0
- package/dist/lib/user-guide-sections.js +488 -0
- package/dist/main.js +10 -2
- package/dist/seeds/agents-md.js +3 -3
- package/dist/utils/agents-md.js +1 -1
- package/dist/utils/guide-paths.js +7 -7
- package/dist/utils/hosted-workspace.js +2 -1
- package/dist/utils/repo-first-storage.js +26 -1
- package/dist/utils/session-state.js +2 -7
- package/launchers/aops-cockpit.sh +0 -0
- package/launchers/aops-server.sh +0 -0
- package/package.json +67 -35
- package/THIRD_PARTY_NOTICES +0 -16169
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/SKILL.md +0 -47
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/agentspace/SKILL.md +0 -72
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/aops-cli-core/SKILL.md +0 -110
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/chatv3/SKILL.md +0 -59
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/collaborative-work/SKILL.md +0 -81
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/discuss/SKILL.md +0 -66
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/docman/SKILL.md +0 -75
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/projectman/SKILL.md +0 -92
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/sys/SKILL.md +0 -36
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/view/SKILL.md +0 -58
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/working-disciplines/SKILL.md +0 -66
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/agent-assets.md +0 -81
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/agentspace.md +0 -183
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/aops-cli.md +0 -1108
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/aops-system.md +0 -102
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/chatv3.md +0 -113
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/docman.md +0 -223
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/projectman.md +0 -233
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/sys.md +0 -94
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/working-disciplines.md +0 -482
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/manifest.json +0 -117
- package/agent-assets-release/agent-assets/gateway/aops/SKILL.md +0 -14
- package/agent-assets-release/agent-assets/inventory.json +0 -29
- package/agent-assets-release/agent-assets/projection.json +0 -8
- package/agent-assets-release/agent-assets-release.json +0 -171
- package/agent-assets-release/agent-assets-release.sigstore.json +0 -67
- package/assets/agent-assets/core/SKILL.md +0 -47
- package/assets/agent-assets/core/references/agentspace/SKILL.md +0 -72
- package/assets/agent-assets/core/references/aops-cli-core/SKILL.md +0 -110
- package/assets/agent-assets/core/references/chatv3/SKILL.md +0 -59
- package/assets/agent-assets/core/references/collaborative-work/SKILL.md +0 -81
- package/assets/agent-assets/core/references/discuss/SKILL.md +0 -66
- package/assets/agent-assets/core/references/docman/SKILL.md +0 -75
- package/assets/agent-assets/core/references/projectman/SKILL.md +0 -92
- package/assets/agent-assets/core/references/sys/SKILL.md +0 -36
- package/assets/agent-assets/core/references/view/SKILL.md +0 -58
- package/assets/agent-assets/core/references/working-disciplines/SKILL.md +0 -66
- package/assets/agent-assets/core/user-guides/agent-assets.md +0 -81
- package/assets/agent-assets/core/user-guides/agentspace.md +0 -183
- package/assets/agent-assets/core/user-guides/aops-cli.md +0 -1108
- package/assets/agent-assets/core/user-guides/aops-system.md +0 -102
- package/assets/agent-assets/core/user-guides/chatv3.md +0 -113
- package/assets/agent-assets/core/user-guides/docman.md +0 -223
- package/assets/agent-assets/core/user-guides/projectman.md +0 -233
- package/assets/agent-assets/core/user-guides/sys.md +0 -94
- package/assets/agent-assets/core/user-guides/working-disciplines.md +0 -482
- package/assets/agent-assets/gateway/aops/SKILL.md +0 -14
- package/dist/lib/agent-assets/gateway.js +0 -15
- package/dist/lib/agent-assets/guards.js +0 -23
- package/dist/lib/agent-assets/hosted-discovery.js +0 -148
- package/dist/lib/agent-assets/hosted-package-input.js +0 -154
- package/dist/lib/agent-assets/legacy-pointer-migration.js +0 -677
- package/dist/lib/agent-assets/native-fs.js +0 -589
- package/dist/lib/agent-assets/roots.js +0 -45
- package/dist/lib/agent-assets/runtime-binding-reader.js +0 -545
- package/dist/lib/agent-assets/runtime-targets.js +0 -50
- package/dist/lib/agent-assets/store-reader.js +0 -1212
- package/dist/lib/agent-assets/store-writer.js +0 -1484
- package/native/bin/darwin-arm64/aops-agent-assets-fs +0 -0
- package/native/bin/darwin-x64/aops-agent-assets-fs +0 -0
- package/native/bin/linux-arm64/aops-agent-assets-fs +0 -0
- package/native/bin/linux-x64/aops-agent-assets-fs +0 -0
- package/native/bin/win32-x64/aops-agent-assets-fs.exe +0 -0
- package/native/manifest.json +0 -49
- package/native/qualifications/win32-x64.json +0 -23
- package/native/tui/darwin-arm64/aops-tui +0 -0
- package/native/tui/linux-x64/aops-tui +0 -0
- package/native/tui/win32-x64/aops-tui.exe +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { compactPayload, normalizeNonEmpty } from '../utils/command.js';
|
|
4
|
+
import { buildOperatorCookbook } from '../utils/hosted-sugar.js';
|
|
5
|
+
import { GUIDE_PATHS } from '../utils/guide-paths.js';
|
|
6
|
+
import { applyTaskerContextOptions, applyTaskerWriteOptions, executeTaskerTool, parseTaskerObject, } from './tasker.js';
|
|
7
|
+
function required(value, flag) {
|
|
8
|
+
const normalized = normalizeNonEmpty(value);
|
|
9
|
+
if (!normalized)
|
|
10
|
+
throw new Error(`${flag} is required unless --input supplies the full hosted-tool input.`);
|
|
11
|
+
return normalized;
|
|
12
|
+
}
|
|
13
|
+
function fullInputOr(options, build) {
|
|
14
|
+
return options.input ? parseTaskerObject(options.input, '--input') : build();
|
|
15
|
+
}
|
|
16
|
+
function addRunnerReadOptions(command) {
|
|
17
|
+
return command
|
|
18
|
+
.option('--run-id <id>', 'Canonical Tasker runner run id')
|
|
19
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
20
|
+
.option('--summary', 'Print a compact Runner projection and omit bulky event/meta payloads');
|
|
21
|
+
}
|
|
22
|
+
export function summarizeRunnerStatusResult(result) {
|
|
23
|
+
if (!result || typeof result !== 'object' || Array.isArray(result))
|
|
24
|
+
return result;
|
|
25
|
+
const envelope = result;
|
|
26
|
+
const data = envelope.data;
|
|
27
|
+
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
28
|
+
return result;
|
|
29
|
+
const record = data;
|
|
30
|
+
if (!record.summary || typeof record.summary !== 'object')
|
|
31
|
+
return result;
|
|
32
|
+
const scheduling = record.scheduling && typeof record.scheduling === 'object' && !Array.isArray(record.scheduling)
|
|
33
|
+
? record.scheduling
|
|
34
|
+
: undefined;
|
|
35
|
+
return {
|
|
36
|
+
...envelope,
|
|
37
|
+
data: compactPayload({
|
|
38
|
+
summary: record.summary,
|
|
39
|
+
scheduling: scheduling
|
|
40
|
+
? compactPayload({
|
|
41
|
+
ready: scheduling.ready,
|
|
42
|
+
waiting: scheduling.waiting,
|
|
43
|
+
blockedByFailure: scheduling.blockedByFailure,
|
|
44
|
+
stalled: scheduling.stalled,
|
|
45
|
+
terminal: scheduling.terminal,
|
|
46
|
+
nextReady: scheduling.nextReady,
|
|
47
|
+
})
|
|
48
|
+
: undefined,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function runRead(options, params) {
|
|
53
|
+
await executeTaskerTool(options, {
|
|
54
|
+
command: params.command,
|
|
55
|
+
toolId: params.toolId,
|
|
56
|
+
successText: params.successText,
|
|
57
|
+
buildInput: () => fullInputOr(options, params.build),
|
|
58
|
+
summarizeResult: params.summarizeResult,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function buildControlInput(options, kind) {
|
|
62
|
+
if (options.input)
|
|
63
|
+
return parseTaskerObject(options.input, '--input');
|
|
64
|
+
const runId = required(options.runId, '--run-id');
|
|
65
|
+
const idempotencyKey = required(options.idempotencyKey, '--idempotency-key');
|
|
66
|
+
return {
|
|
67
|
+
reconcileState: {
|
|
68
|
+
schemaVersion: 'tasker.loop-runner.v2',
|
|
69
|
+
runId,
|
|
70
|
+
reconcileId: normalizeNonEmpty(options.reconcileId) ?? randomUUID(),
|
|
71
|
+
kind,
|
|
72
|
+
state: normalizeNonEmpty(options.state) ?? 'pending',
|
|
73
|
+
requestedBy: {
|
|
74
|
+
kind: 'operator',
|
|
75
|
+
id: normalizeNonEmpty(options.operatorId) ?? 'aops-cli',
|
|
76
|
+
},
|
|
77
|
+
requestedAt: normalizeNonEmpty(options.requestedAt) ?? new Date().toISOString(),
|
|
78
|
+
replaysCanonicalWrites: false,
|
|
79
|
+
idempotencyKey,
|
|
80
|
+
},
|
|
81
|
+
idempotencyKey,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function addControlCommand(root, name) {
|
|
85
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(root.command(name)
|
|
86
|
+
.description(`${name === 'stop' ? 'Stop' : 'Resume'} a Tasker runner run through the guarded control surface`)
|
|
87
|
+
.option('--run-id <id>', 'Canonical Tasker runner run id')
|
|
88
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
89
|
+
.option('--reconcile-id <id>', 'Optional reconcile id; defaults to a generated UUID')
|
|
90
|
+
.option('--state <state>', 'Reconcile state', 'pending')
|
|
91
|
+
.option('--operator-id <id>', 'Operator actor id', 'aops-cli')
|
|
92
|
+
.option('--requested-at <timestamp>', 'Operator request timestamp; defaults to now')).action(async (options) => {
|
|
93
|
+
await executeTaskerTool(options, {
|
|
94
|
+
command: `runner.${name}`,
|
|
95
|
+
toolId: `tasker.loop-runner-v2.control.${name}`,
|
|
96
|
+
write: true,
|
|
97
|
+
successText: `Tasker runner ${name} request completed.`,
|
|
98
|
+
buildInput: () => buildControlInput(options, name),
|
|
99
|
+
});
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
export function makeRunnerCommand() {
|
|
103
|
+
const command = new Command('runner').description('Tasker Loop Runner v2 status and guarded control sugar');
|
|
104
|
+
applyTaskerContextOptions(addRunnerReadOptions(command.command('status').description('Get a Tasker runner status snapshot'))
|
|
105
|
+
.option('--include-events', 'Include recent events')
|
|
106
|
+
.option('--include-artifacts', 'Include artifact refs')
|
|
107
|
+
.action(async (options) => {
|
|
108
|
+
await runRead(options, {
|
|
109
|
+
command: 'runner.status',
|
|
110
|
+
toolId: 'tasker.loop-runner-v2.status.get',
|
|
111
|
+
successText: 'Tasker runner status loaded.',
|
|
112
|
+
summarizeResult: summarizeRunnerStatusResult,
|
|
113
|
+
build: () => compactPayload({
|
|
114
|
+
runId: required(options.runId, '--run-id'),
|
|
115
|
+
includeEvents: options.includeEvents === true ? true : undefined,
|
|
116
|
+
includeArtifacts: options.includeArtifacts === true ? true : undefined,
|
|
117
|
+
}),
|
|
118
|
+
});
|
|
119
|
+
}));
|
|
120
|
+
const event = command.command('event').description('Tasker runner event reads');
|
|
121
|
+
applyTaskerContextOptions(addRunnerReadOptions(event.command('list').description('List events for a Tasker runner run'))
|
|
122
|
+
.option('--slice-id <id>', 'Optional slice id filter')
|
|
123
|
+
.option('--after-sequence <value>', 'Return events after this sequence', (value) => Number.parseInt(String(value), 10))
|
|
124
|
+
.option('--limit <value>', 'Result limit', (value) => Number.parseInt(String(value), 10))
|
|
125
|
+
.action(async (options) => {
|
|
126
|
+
await runRead(options, {
|
|
127
|
+
command: 'runner.event.list',
|
|
128
|
+
toolId: 'tasker.loop-runner-v2.event.list',
|
|
129
|
+
successText: 'Tasker runner events loaded.',
|
|
130
|
+
build: () => compactPayload({
|
|
131
|
+
runId: required(options.runId, '--run-id'),
|
|
132
|
+
sliceId: options.sliceId,
|
|
133
|
+
afterSequence: options.afterSequence,
|
|
134
|
+
limit: options.limit,
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
}));
|
|
138
|
+
const artifact = command.command('artifact').description('Tasker runner artifact reads');
|
|
139
|
+
applyTaskerContextOptions(addRunnerReadOptions(artifact.command('list').description('List artifact refs for a Tasker runner run'))
|
|
140
|
+
.option('--slice-id <id>', 'Optional slice id filter')
|
|
141
|
+
.option('--kind <kind>', 'Optional artifact kind filter')
|
|
142
|
+
.option('--limit <value>', 'Result limit', (value) => Number.parseInt(String(value), 10))
|
|
143
|
+
.action(async (options) => {
|
|
144
|
+
await runRead(options, {
|
|
145
|
+
command: 'runner.artifact.list',
|
|
146
|
+
toolId: 'tasker.loop-runner-v2.artifact.list',
|
|
147
|
+
successText: 'Tasker runner artifacts loaded.',
|
|
148
|
+
build: () => compactPayload({
|
|
149
|
+
runId: required(options.runId, '--run-id'),
|
|
150
|
+
sliceId: options.sliceId,
|
|
151
|
+
kind: options.kind,
|
|
152
|
+
limit: options.limit,
|
|
153
|
+
}),
|
|
154
|
+
});
|
|
155
|
+
}));
|
|
156
|
+
const worker = command.command('worker').description('Tasker runner atomic worker lease operations');
|
|
157
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(worker.command('claim')
|
|
158
|
+
.description('Atomically claim the next ready slice, or one explicit ready slice with --slice-id')
|
|
159
|
+
.option('--run-id <id>', 'Canonical Tasker runner run id')
|
|
160
|
+
.option('--slice-id <id>', 'Optional explicit ready slice; omit for deterministic claim-next')
|
|
161
|
+
.option('--lease-id <id>', 'Lease id; defaults to a generated UUID')
|
|
162
|
+
.option('--worker-id <id>', 'Worker identity', 'aops-cli')
|
|
163
|
+
.option('--runtime-key <key>', 'Worker runtime key', 'aops-cli-loop')
|
|
164
|
+
.option('--claimed-at <timestamp>', 'Claim timestamp; defaults to now')
|
|
165
|
+
.option('--expires-at <timestamp>', 'Lease expiry; defaults to claimed-at plus --ttl-sec')
|
|
166
|
+
.option('--ttl-sec <seconds>', 'Default lease TTL when --expires-at is omitted', (value) => Number.parseInt(String(value), 10), 300)
|
|
167
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')).action(async (options) => {
|
|
168
|
+
await executeTaskerTool(options, {
|
|
169
|
+
command: 'runner.worker.claim',
|
|
170
|
+
toolId: 'tasker.loop-runner-v2.worker.claim',
|
|
171
|
+
write: true,
|
|
172
|
+
successText: 'Tasker runner worker lease claim completed.',
|
|
173
|
+
buildInput: () => fullInputOr(options, () => {
|
|
174
|
+
const claimedAt = new Date(normalizeNonEmpty(options.claimedAt) ?? Date.now());
|
|
175
|
+
const ttlSec = Number.isInteger(options.ttlSec) && Number(options.ttlSec) > 0 ? Number(options.ttlSec) : 300;
|
|
176
|
+
const expiresAt = normalizeNonEmpty(options.expiresAt)
|
|
177
|
+
? new Date(String(options.expiresAt))
|
|
178
|
+
: new Date(claimedAt.getTime() + ttlSec * 1000);
|
|
179
|
+
return compactPayload({
|
|
180
|
+
runId: required(options.runId, '--run-id'),
|
|
181
|
+
sliceId: options.sliceId,
|
|
182
|
+
leaseId: normalizeNonEmpty(options.leaseId) ?? randomUUID(),
|
|
183
|
+
workerId: normalizeNonEmpty(options.workerId) ?? 'aops-cli',
|
|
184
|
+
runtimeKey: normalizeNonEmpty(options.runtimeKey) ?? 'aops-cli-loop',
|
|
185
|
+
permissions: {
|
|
186
|
+
canSpawnNestedAgents: false,
|
|
187
|
+
canMerge: false,
|
|
188
|
+
canAccessSecrets: false,
|
|
189
|
+
requiresForegroundSupervision: true,
|
|
190
|
+
},
|
|
191
|
+
claimedAt: claimedAt.toISOString(),
|
|
192
|
+
expiresAt: expiresAt.toISOString(),
|
|
193
|
+
idempotencyKey: required(options.idempotencyKey, '--idempotency-key'),
|
|
194
|
+
});
|
|
195
|
+
}),
|
|
196
|
+
});
|
|
197
|
+
}));
|
|
198
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(worker.command('release')
|
|
199
|
+
.description('Atomically release, cancel, or fail one worker lease')
|
|
200
|
+
.option('--run-id <id>', 'Canonical Tasker runner run id')
|
|
201
|
+
.option('--lease-id <id>', 'Lease id')
|
|
202
|
+
.option('--worker-id <id>', 'Optional worker identity guard')
|
|
203
|
+
.option('--terminal-state <state>', 'released | cancelled | failed', 'released')
|
|
204
|
+
.option('--released-at <timestamp>', 'Terminal transition timestamp; defaults to now')
|
|
205
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')).action(async (options) => {
|
|
206
|
+
await executeTaskerTool(options, {
|
|
207
|
+
command: 'runner.worker.release',
|
|
208
|
+
toolId: 'tasker.loop-runner-v2.worker.release',
|
|
209
|
+
write: true,
|
|
210
|
+
successText: 'Tasker runner worker lease release completed.',
|
|
211
|
+
buildInput: () => fullInputOr(options, () => compactPayload({
|
|
212
|
+
runId: required(options.runId, '--run-id'),
|
|
213
|
+
leaseId: required(options.leaseId, '--lease-id'),
|
|
214
|
+
workerId: options.workerId,
|
|
215
|
+
terminalState: normalizeNonEmpty(options.terminalState) ?? 'released',
|
|
216
|
+
releasedAt: new Date(normalizeNonEmpty(options.releasedAt) ?? Date.now()).toISOString(),
|
|
217
|
+
idempotencyKey: required(options.idempotencyKey, '--idempotency-key'),
|
|
218
|
+
})),
|
|
219
|
+
});
|
|
220
|
+
}));
|
|
221
|
+
addControlCommand(command, 'stop');
|
|
222
|
+
addControlCommand(command, 'resume');
|
|
223
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(command.command('reconcile')
|
|
224
|
+
.description('Request a guarded Tasker runner reconciliation')
|
|
225
|
+
.option('--run-id <id>', 'Canonical Tasker runner run id')
|
|
226
|
+
.option('--kind <kind>', 'Reconcile kind: cleanup, status, cost-usage, artifact, or review')
|
|
227
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
228
|
+
.option('--reconcile-id <id>', 'Optional reconcile id; defaults to a generated UUID')
|
|
229
|
+
.option('--state <state>', 'Reconcile state', 'pending')
|
|
230
|
+
.option('--operator-id <id>', 'Operator actor id', 'aops-cli')
|
|
231
|
+
.option('--requested-at <timestamp>', 'Operator request timestamp; defaults to now')).action(async (options) => {
|
|
232
|
+
const kind = options.input ? 'status' : required(options.kind, '--kind');
|
|
233
|
+
await executeTaskerTool(options, {
|
|
234
|
+
command: 'runner.reconcile',
|
|
235
|
+
toolId: 'tasker.loop-runner-v2.control.reconcile',
|
|
236
|
+
write: true,
|
|
237
|
+
successText: 'Tasker runner reconcile request completed.',
|
|
238
|
+
buildInput: () => buildControlInput(options, kind),
|
|
239
|
+
});
|
|
240
|
+
}));
|
|
241
|
+
command.addHelpText('after', buildOperatorCookbook({
|
|
242
|
+
examples: [
|
|
243
|
+
'aops runner status --run-id <run-id> --include-events --json',
|
|
244
|
+
'aops runner worker claim --run-id <run-id> --worker-id <worker-id> --idempotency-key <key> --apply --json',
|
|
245
|
+
'aops runner worker release --run-id <run-id> --lease-id <lease-id> --terminal-state released --idempotency-key <key> --apply --json',
|
|
246
|
+
'aops runner stop --run-id <run-id> --idempotency-key <key> --preview --json',
|
|
247
|
+
'aops runner reconcile --run-id <run-id> --kind status --idempotency-key <key> --apply --json',
|
|
248
|
+
'aops agent schema --tool tasker.loop-runner-v2.status.get --summary --json',
|
|
249
|
+
],
|
|
250
|
+
guide: GUIDE_PATHS.tasker,
|
|
251
|
+
notes: [
|
|
252
|
+
'Runner sugar delegates to Tasker Loop Runner v2 hosted operations; it is not a second executor.',
|
|
253
|
+
'Runner control writes require --preview or --apply.',
|
|
254
|
+
],
|
|
255
|
+
}));
|
|
256
|
+
return command;
|
|
257
|
+
}
|
package/dist/commands/skill.js
CHANGED
|
@@ -1197,7 +1197,7 @@ export function makeSkillCommand() {
|
|
|
1197
1197
|
guide: GUIDE_PATHS.agentspace,
|
|
1198
1198
|
notes: [
|
|
1199
1199
|
'Canonical reusable skill truth lives in aops-server/DB; create/update/publish through these skill commands.',
|
|
1200
|
-
'.aops/hosted/skills/** is a read-only repo mirror refreshed by sync pull/bootstrap, not an authoring source.',
|
|
1200
|
+
'.aops-cache/hosted/skills/** is a read-only repo mirror refreshed by sync pull/bootstrap, not an authoring source.',
|
|
1201
1201
|
'Skill version list/inspect/current are curated read surfaces and do not require --apply.',
|
|
1202
1202
|
'skill search/ask inspect only current published package metadata; they do not load skill bodies or maintain a local search index.',
|
|
1203
1203
|
'skill ask is a deterministic projection of one skill search result, not an LLM-generated semantic answer.',
|
package/dist/commands/start.js
CHANGED
|
@@ -11,7 +11,7 @@ import { buildSessionGuidancePack } from '../utils/session-guidance.js';
|
|
|
11
11
|
import { buildReadOnlyRepoFirstMemoryBriefFromContext } from './memory.js';
|
|
12
12
|
import { applyCommonOptions, compactPayload } from '../utils/command.js';
|
|
13
13
|
import { START_DISCIPLINES, START_DISCIPLINE_PROFILES, startGuardrailsForDiscipline, } from './start-disciplines.js';
|
|
14
|
-
export const START_PROMPT_MIRROR_PATH = '.aops/hosted/prompts/aops-collaborative-startup.md';
|
|
14
|
+
export const START_PROMPT_MIRROR_PATH = '.aops-cache/hosted/prompts/aops-collaborative-startup.md';
|
|
15
15
|
export const START_MODES = ['solo', 'solo+async-review', 'chat-room'];
|
|
16
16
|
export const START_METHODS = START_DISCIPLINES;
|
|
17
17
|
const MULTI_AGENT_MODES = new Set(['chat-room']);
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { logSuccess } from '@aopslabs/xf-cli-ui';
|
|
3
|
+
import { applyCommonOptions, compactPayload, normalizeNonEmpty } from '../utils/command.js';
|
|
4
|
+
import { invokeHostedToolWithApiState, parseJsonInput, requireApiState, resolveAgentGatewayContext, resolveProjectScopeOptionsWithApiState, unwrapHostedToolResult, } from '../utils/agent-gateway.js';
|
|
5
|
+
import { buildHostedSugarEnvelope, buildOperatorCookbook, ensureGuardedWrite, } from '../utils/hosted-sugar.js';
|
|
6
|
+
import { GUIDE_PATHS } from '../utils/guide-paths.js';
|
|
7
|
+
const TASKER_SUMMARY_FIELDS = [
|
|
8
|
+
'id', 'scopeId', 'projectId', 'boardId', 'columnId', 'workGroupId', 'parentTaskId',
|
|
9
|
+
'runId', 'sliceId', 'eventId', 'eventType', 'sequence', 'artifactId', 'kind', 'uri',
|
|
10
|
+
'latestSequence', 'name', 'title', 'type', 'status', 'position', 'priority', 'assignee', 'dueAt',
|
|
11
|
+
'createdAt', 'updatedAt',
|
|
12
|
+
];
|
|
13
|
+
function summarizeTaskerRecord(value) {
|
|
14
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
15
|
+
return value;
|
|
16
|
+
const record = value;
|
|
17
|
+
const summary = {};
|
|
18
|
+
for (const key of TASKER_SUMMARY_FIELDS) {
|
|
19
|
+
if (record[key] !== undefined)
|
|
20
|
+
summary[key] = record[key];
|
|
21
|
+
}
|
|
22
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
23
|
+
if (!Array.isArray(entry))
|
|
24
|
+
continue;
|
|
25
|
+
summary[`${key}Count`] = entry.length;
|
|
26
|
+
if (key === 'events' || key === 'artifactRefs') {
|
|
27
|
+
summary[key] = entry.map(summarizeTaskerRecord);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return Object.keys(summary).length > 0 ? summary : value;
|
|
31
|
+
}
|
|
32
|
+
export function summarizeTaskerReadResult(result) {
|
|
33
|
+
if (!result || typeof result !== 'object' || Array.isArray(result))
|
|
34
|
+
return result;
|
|
35
|
+
const envelope = result;
|
|
36
|
+
const data = envelope.data;
|
|
37
|
+
if (Array.isArray(data)) {
|
|
38
|
+
return { ...envelope, data: data.map(summarizeTaskerRecord) };
|
|
39
|
+
}
|
|
40
|
+
if (!data || typeof data !== 'object')
|
|
41
|
+
return result;
|
|
42
|
+
const dataRecord = data;
|
|
43
|
+
if (Array.isArray(dataRecord.items)) {
|
|
44
|
+
return { ...envelope, data: { ...dataRecord, items: dataRecord.items.map(summarizeTaskerRecord) } };
|
|
45
|
+
}
|
|
46
|
+
return { ...envelope, data: summarizeTaskerRecord(dataRecord) };
|
|
47
|
+
}
|
|
48
|
+
export function applyTaskerContextOptions(command) {
|
|
49
|
+
applyCommonOptions(command, { withProject: false });
|
|
50
|
+
command.option('--scope-id <id>', 'Canonical Tasker owner scope override');
|
|
51
|
+
command.option('--project-id <id>', 'Project id used by Tasker scope-aware operations');
|
|
52
|
+
command.option('--project-name <name>', 'Project name override for repo-aware context resolution');
|
|
53
|
+
command.option('--project-slug <slug>', 'Project slug from the repo project registry');
|
|
54
|
+
command.option('--tenant-id <id>', 'Tenant id header (x-tenant-id)');
|
|
55
|
+
command.option('--locale <locale>', 'Locale header (x-locale)');
|
|
56
|
+
command.option('--fallback-locale <locale>', 'Fallback locale header (x-fallback-locale)');
|
|
57
|
+
return command;
|
|
58
|
+
}
|
|
59
|
+
export function applyTaskerWriteOptions(command) {
|
|
60
|
+
command.option('--preview', 'Validate and preview the hosted write without applying it');
|
|
61
|
+
command.option('--apply', 'Explicitly allow the hosted write');
|
|
62
|
+
command.option('--idempotency-key <key>', 'Optional guarded-write idempotency key');
|
|
63
|
+
return command;
|
|
64
|
+
}
|
|
65
|
+
export function parseTaskerObject(value, label) {
|
|
66
|
+
const parsed = parseJsonInput(value, label);
|
|
67
|
+
if (parsed === undefined)
|
|
68
|
+
return {};
|
|
69
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
70
|
+
throw new Error(`${label} must be a JSON object.`);
|
|
71
|
+
}
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
function required(value, flag) {
|
|
75
|
+
const normalized = normalizeNonEmpty(value);
|
|
76
|
+
if (!normalized)
|
|
77
|
+
throw new Error(`${flag} is required unless --input supplies the full hosted-tool input.`);
|
|
78
|
+
return normalized;
|
|
79
|
+
}
|
|
80
|
+
function scopedFilter(filter, context, includeProject) {
|
|
81
|
+
return compactPayload({
|
|
82
|
+
scopeId: context.scopeId,
|
|
83
|
+
projectId: includeProject ? context.projectId : undefined,
|
|
84
|
+
...filter,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function fullInputOr(options, build) {
|
|
88
|
+
return options.input ? parseTaskerObject(options.input, '--input') : build();
|
|
89
|
+
}
|
|
90
|
+
export async function executeTaskerTool(options, params) {
|
|
91
|
+
if (params.write) {
|
|
92
|
+
ensureGuardedWrite(options, 'This command mutates Tasker state.');
|
|
93
|
+
}
|
|
94
|
+
const apiState = await requireApiState(options);
|
|
95
|
+
if (!apiState)
|
|
96
|
+
return;
|
|
97
|
+
const scopedOptions = await resolveProjectScopeOptionsWithApiState(apiState, options);
|
|
98
|
+
const resolvedContext = await resolveAgentGatewayContext(scopedOptions);
|
|
99
|
+
const input = params.buildInput(resolvedContext);
|
|
100
|
+
const payload = await invokeHostedToolWithApiState(apiState, {
|
|
101
|
+
...scopedOptions,
|
|
102
|
+
toolId: params.toolId,
|
|
103
|
+
input,
|
|
104
|
+
preview: options.preview,
|
|
105
|
+
apply: options.apply,
|
|
106
|
+
idempotencyKey: options.idempotencyKey,
|
|
107
|
+
});
|
|
108
|
+
const result = unwrapHostedToolResult(payload);
|
|
109
|
+
const outputResult = options.summary
|
|
110
|
+
? (params.summarizeResult ?? summarizeTaskerReadResult)(result)
|
|
111
|
+
: result;
|
|
112
|
+
if (options.json) {
|
|
113
|
+
console.log(JSON.stringify(buildHostedSugarEnvelope({
|
|
114
|
+
command: params.command,
|
|
115
|
+
toolId: params.toolId,
|
|
116
|
+
surface: 'tasker hosted sugar',
|
|
117
|
+
resolvedContext: compactPayload(resolvedContext),
|
|
118
|
+
input,
|
|
119
|
+
result: outputResult,
|
|
120
|
+
}), null, 2));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
logSuccess(options.preview ? `${params.command} preview completed.` : params.successText);
|
|
124
|
+
console.log(JSON.stringify(outputResult, null, 2));
|
|
125
|
+
}
|
|
126
|
+
function listInput(options, context, includeProject) {
|
|
127
|
+
return fullInputOr(options, () => {
|
|
128
|
+
const listOptions = parseTaskerObject(options.options, '--options');
|
|
129
|
+
return compactPayload({
|
|
130
|
+
filter: scopedFilter(parseTaskerObject(options.filter, '--filter'), context, includeProject),
|
|
131
|
+
options: Object.keys(listOptions).length > 0 ? listOptions : undefined,
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function getInput(options) {
|
|
136
|
+
return fullInputOr(options, () => {
|
|
137
|
+
const getOptions = parseTaskerObject(options.options, '--options');
|
|
138
|
+
return compactPayload({
|
|
139
|
+
id: required(options.id, '--id'),
|
|
140
|
+
options: Object.keys(getOptions).length > 0 ? getOptions : undefined,
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function addListJsonOptions(command) {
|
|
145
|
+
return command
|
|
146
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
147
|
+
.option('--filter <json|@file>', 'Filter JSON object')
|
|
148
|
+
.option('--options <json|@file>', 'List options JSON object')
|
|
149
|
+
.option('--summary', 'Print compact Tasker records and omit bulky fields');
|
|
150
|
+
}
|
|
151
|
+
function addGetJsonOptions(command) {
|
|
152
|
+
return command
|
|
153
|
+
.option('--id <id>', 'Canonical record id')
|
|
154
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
155
|
+
.option('--options <json|@file>', 'Get options JSON object')
|
|
156
|
+
.option('--summary', 'Print a compact Tasker record and omit bulky fields');
|
|
157
|
+
}
|
|
158
|
+
function addBoardCommands(root) {
|
|
159
|
+
const board = root.command('board').description('Tasker kanban-board commands');
|
|
160
|
+
applyTaskerContextOptions(addListJsonOptions(board.command('list').description('List Tasker kanban boards'))
|
|
161
|
+
.action(async (options) => {
|
|
162
|
+
await executeTaskerTool(options, {
|
|
163
|
+
command: 'tasker.board.list',
|
|
164
|
+
toolId: 'tasker.kanban-board.list-boards',
|
|
165
|
+
successText: 'Tasker boards loaded.',
|
|
166
|
+
buildInput: (context) => listInput(options, context, true),
|
|
167
|
+
});
|
|
168
|
+
}));
|
|
169
|
+
applyTaskerContextOptions(addGetJsonOptions(board.command('get').description('Get a Tasker kanban board by id'))
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
await executeTaskerTool(options, {
|
|
172
|
+
command: 'tasker.board.get',
|
|
173
|
+
toolId: 'tasker.kanban-board.get-by-id',
|
|
174
|
+
successText: 'Tasker board loaded.',
|
|
175
|
+
buildInput: () => getInput(options),
|
|
176
|
+
});
|
|
177
|
+
}));
|
|
178
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(board.command('create')
|
|
179
|
+
.description('Create a Tasker kanban board')
|
|
180
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
181
|
+
.option('--data <json|@file>', 'Board data JSON object')
|
|
182
|
+
.option('--name <name>', 'Board name')
|
|
183
|
+
.option('--description <text>', 'Board description')).action(async (options) => {
|
|
184
|
+
await executeTaskerTool(options, {
|
|
185
|
+
command: 'tasker.board.create',
|
|
186
|
+
toolId: 'tasker.kanban-board.create',
|
|
187
|
+
write: true,
|
|
188
|
+
successText: 'Tasker board write completed.',
|
|
189
|
+
buildInput: (context) => fullInputOr(options, () => {
|
|
190
|
+
const data = parseTaskerObject(options.data, '--data');
|
|
191
|
+
return {
|
|
192
|
+
data: compactPayload({
|
|
193
|
+
scopeId: context.scopeId,
|
|
194
|
+
projectId: context.projectId,
|
|
195
|
+
...data,
|
|
196
|
+
name: normalizeNonEmpty(options.name) ?? data.name,
|
|
197
|
+
description: normalizeNonEmpty(options.description) ?? data.description,
|
|
198
|
+
}),
|
|
199
|
+
};
|
|
200
|
+
}),
|
|
201
|
+
});
|
|
202
|
+
}));
|
|
203
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(board.command('update')
|
|
204
|
+
.description('Update a Tasker kanban board')
|
|
205
|
+
.option('--id <id>', 'Canonical board id')
|
|
206
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
207
|
+
.option('--patch <json|@file>', 'Board patch JSON object')
|
|
208
|
+
.option('--name <name>', 'Updated board name')
|
|
209
|
+
.option('--description <text>', 'Updated board description')).action(async (options) => {
|
|
210
|
+
await executeTaskerTool(options, {
|
|
211
|
+
command: 'tasker.board.update',
|
|
212
|
+
toolId: 'tasker.kanban-board.update-board',
|
|
213
|
+
write: true,
|
|
214
|
+
successText: 'Tasker board write completed.',
|
|
215
|
+
buildInput: () => fullInputOr(options, () => ({
|
|
216
|
+
id: required(options.id, '--id'),
|
|
217
|
+
patch: compactPayload({
|
|
218
|
+
...parseTaskerObject(options.patch, '--patch'),
|
|
219
|
+
name: options.name,
|
|
220
|
+
description: options.description,
|
|
221
|
+
}),
|
|
222
|
+
})),
|
|
223
|
+
});
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
function addTaskCommands(root) {
|
|
227
|
+
const task = root.command('task').description('Tasker task commands');
|
|
228
|
+
applyTaskerContextOptions(addListJsonOptions(task.command('list').description('Search Tasker tasks'))
|
|
229
|
+
.action(async (options) => {
|
|
230
|
+
await executeTaskerTool(options, {
|
|
231
|
+
command: 'tasker.task.list',
|
|
232
|
+
toolId: 'tasker.task.search-tasks',
|
|
233
|
+
successText: 'Tasker tasks loaded.',
|
|
234
|
+
buildInput: (context) => listInput(options, context, false),
|
|
235
|
+
});
|
|
236
|
+
}));
|
|
237
|
+
applyTaskerContextOptions(addGetJsonOptions(task.command('get').description('Get a Tasker task by id'))
|
|
238
|
+
.action(async (options) => {
|
|
239
|
+
await executeTaskerTool(options, {
|
|
240
|
+
command: 'tasker.task.get',
|
|
241
|
+
toolId: 'tasker.task.get-task',
|
|
242
|
+
successText: 'Tasker task loaded.',
|
|
243
|
+
buildInput: () => getInput(options),
|
|
244
|
+
});
|
|
245
|
+
}));
|
|
246
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(task.command('create')
|
|
247
|
+
.description('Create a Tasker task')
|
|
248
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
249
|
+
.option('--data <json|@file>', 'Task data JSON object')
|
|
250
|
+
.option('--title <title>', 'Task title')
|
|
251
|
+
.option('--column <id>', 'Canonical Tasker column id')
|
|
252
|
+
.option('--type <type>', 'Task type: epic, story, task, bug, chore, or spike')
|
|
253
|
+
.option('--position <index>', 'Optional column position', (value) => Number.parseInt(String(value), 10))
|
|
254
|
+
.option('--description <text>', 'Task description')
|
|
255
|
+
.option('--work-group-id <id>', 'Optional WorkGroup id')
|
|
256
|
+
.option('--assignee <value>', 'Optional assignee')
|
|
257
|
+
.option('--priority <value>', 'Optional numeric priority', (value) => Number.parseInt(String(value), 10))
|
|
258
|
+
.option('--due-at <timestamp>', 'Optional due timestamp')).action(async (options) => {
|
|
259
|
+
await executeTaskerTool(options, {
|
|
260
|
+
command: 'tasker.task.create',
|
|
261
|
+
toolId: 'tasker.task.create-task',
|
|
262
|
+
write: true,
|
|
263
|
+
successText: 'Tasker task write completed.',
|
|
264
|
+
buildInput: (context) => fullInputOr(options, () => {
|
|
265
|
+
const data = parseTaskerObject(options.data, '--data');
|
|
266
|
+
return {
|
|
267
|
+
data: compactPayload({
|
|
268
|
+
scopeId: context.scopeId,
|
|
269
|
+
...data,
|
|
270
|
+
title: normalizeNonEmpty(options.title) ?? data.title,
|
|
271
|
+
columnId: normalizeNonEmpty(options.column) ?? data.columnId,
|
|
272
|
+
type: normalizeNonEmpty(options.type) ?? data.type ?? 'task',
|
|
273
|
+
position: options.position ?? data.position,
|
|
274
|
+
description: normalizeNonEmpty(options.description) ?? data.description,
|
|
275
|
+
workGroupId: normalizeNonEmpty(options.workGroupId) ?? data.workGroupId,
|
|
276
|
+
assignee: normalizeNonEmpty(options.assignee) ?? data.assignee,
|
|
277
|
+
priority: options.priority ?? data.priority,
|
|
278
|
+
dueAt: normalizeNonEmpty(options.dueAt) ?? data.dueAt,
|
|
279
|
+
}),
|
|
280
|
+
};
|
|
281
|
+
}),
|
|
282
|
+
});
|
|
283
|
+
}));
|
|
284
|
+
applyTaskerContextOptions(applyTaskerWriteOptions(task.command('update')
|
|
285
|
+
.description('Update a Tasker task')
|
|
286
|
+
.option('--id <id>', 'Canonical task id')
|
|
287
|
+
.option('--input <json|@file>', 'Full hosted-tool input JSON escape hatch')
|
|
288
|
+
.option('--patch <json|@file>', 'Task patch JSON object')
|
|
289
|
+
.option('--title <title>', 'Updated title')
|
|
290
|
+
.option('--column <id>', 'Updated column id')
|
|
291
|
+
.option('--type <type>', 'Updated task type')
|
|
292
|
+
.option('--position <index>', 'Updated column position', (value) => Number.parseInt(String(value), 10))
|
|
293
|
+
.option('--description <text>', 'Updated description')
|
|
294
|
+
.option('--work-group-id <id>', 'Updated WorkGroup id')
|
|
295
|
+
.option('--assignee <value>', 'Updated assignee')
|
|
296
|
+
.option('--priority <value>', 'Updated numeric priority', (value) => Number.parseInt(String(value), 10))
|
|
297
|
+
.option('--due-at <timestamp>', 'Updated due timestamp')).action(async (options) => {
|
|
298
|
+
await executeTaskerTool(options, {
|
|
299
|
+
command: 'tasker.task.update',
|
|
300
|
+
toolId: 'tasker.task.update-task',
|
|
301
|
+
write: true,
|
|
302
|
+
successText: 'Tasker task write completed.',
|
|
303
|
+
buildInput: () => fullInputOr(options, () => ({
|
|
304
|
+
id: required(options.id, '--id'),
|
|
305
|
+
patch: compactPayload({
|
|
306
|
+
...parseTaskerObject(options.patch, '--patch'),
|
|
307
|
+
title: options.title,
|
|
308
|
+
columnId: options.column,
|
|
309
|
+
type: options.type,
|
|
310
|
+
position: options.position,
|
|
311
|
+
description: options.description,
|
|
312
|
+
workGroupId: options.workGroupId,
|
|
313
|
+
assignee: options.assignee,
|
|
314
|
+
priority: options.priority,
|
|
315
|
+
dueAt: options.dueAt,
|
|
316
|
+
}),
|
|
317
|
+
})),
|
|
318
|
+
});
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
function addWorkGroupCommands(root) {
|
|
322
|
+
const workGroup = root.command('work-group').alias('workgroup').description('Tasker WorkGroup read commands');
|
|
323
|
+
applyTaskerContextOptions(addListJsonOptions(workGroup.command('list').description('List Tasker WorkGroups'))
|
|
324
|
+
.action(async (options) => {
|
|
325
|
+
await executeTaskerTool(options, {
|
|
326
|
+
command: 'tasker.work-group.list',
|
|
327
|
+
toolId: 'tasker.work-group.list-work-groups',
|
|
328
|
+
successText: 'Tasker WorkGroups loaded.',
|
|
329
|
+
buildInput: (context) => listInput(options, context, false),
|
|
330
|
+
});
|
|
331
|
+
}));
|
|
332
|
+
applyTaskerContextOptions(addGetJsonOptions(workGroup.command('get').description('Get a Tasker WorkGroup by id'))
|
|
333
|
+
.action(async (options) => {
|
|
334
|
+
await executeTaskerTool(options, {
|
|
335
|
+
command: 'tasker.work-group.get',
|
|
336
|
+
toolId: 'tasker.work-group.get-work-group',
|
|
337
|
+
successText: 'Tasker WorkGroup loaded.',
|
|
338
|
+
buildInput: () => getInput(options),
|
|
339
|
+
});
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
export function makeTaskerCommand() {
|
|
343
|
+
const command = new Command('tasker').description('Tasker board, task, and WorkGroup sugar over the hosted AOPS plane');
|
|
344
|
+
addBoardCommands(command);
|
|
345
|
+
addTaskCommands(command);
|
|
346
|
+
addWorkGroupCommands(command);
|
|
347
|
+
command.addHelpText('after', buildOperatorCookbook({
|
|
348
|
+
examples: [
|
|
349
|
+
'aops tasker board list --project-slug <slug> --json',
|
|
350
|
+
'aops tasker task create --scope-id <scope-id> --column <column-id> --title "Implement slice" --preview --json',
|
|
351
|
+
'aops tasker work-group list --scope-id <scope-id> --json',
|
|
352
|
+
'aops agent schema --tool tasker.task.create-task --summary --json',
|
|
353
|
+
],
|
|
354
|
+
guide: GUIDE_PATHS.tasker,
|
|
355
|
+
notes: [
|
|
356
|
+
'Sugar accepts canonical ids; use `aops agent tools --domain tasker --summary --json` for the complete hosted operation catalog.',
|
|
357
|
+
'Tasker sugar contract checks are app-owned: `pnpm --filter @aopslabs/aops run test:tasker-sugar`.',
|
|
358
|
+
],
|
|
359
|
+
}));
|
|
360
|
+
return command;
|
|
361
|
+
}
|