tines 0.0.323 → 0.0.324
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 +7 -0
- package/dist/index.js +70 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ tines issues create <project> --title "…" -d @description.md
|
|
|
40
40
|
tines issues create <project> --title "Linked" --blocked-by Other/12 --blocks Other/14 --duplicate-of Other/9
|
|
41
41
|
tines issues show <project>/<number>
|
|
42
42
|
tines issues move <project>/<number> <action> # a workflow transition
|
|
43
|
+
tines issues move <project>/<number> <action> --expect-revision <n> # refuse unless the issue is still at the decision revision `issues show` printed
|
|
43
44
|
tines issues hold <project>/<number> # stop new admission, keep permission
|
|
44
45
|
tines issues release <project>/<number> # resume eligibility if permission remains on
|
|
45
46
|
tines issues cancel-run <project>/<number> <run-id> # request bounded cancellation
|
|
@@ -81,6 +82,12 @@ every evidence page with no ceiling and takes no `--max-items`.
|
|
|
81
82
|
When a recurrence is also supplied, the relationships apply only to the first issue; later
|
|
82
83
|
scheduled instances start without copied relationships.
|
|
83
84
|
|
|
85
|
+
`workflows show` prints a workflow's `revision`, which advances by one on every committed
|
|
86
|
+
save. `workflows edit <workflow> … --expect-revision <n>` (or `"expected_revision"` in the
|
|
87
|
+
JSON body; the flag wins) refuses the update with `workflow_conflict`, writing nothing, when
|
|
88
|
+
the workflow is no longer at that revision. The CLI never fills the revision in for you and
|
|
89
|
+
never retries: re-read with `workflows show`, re-apply your change, and send the new revision.
|
|
90
|
+
|
|
84
91
|
For a shared project's recurring schedule, `schedules list` and `schedules show` report
|
|
85
92
|
your saved future-instance permission and its epoch. They are read receipts: the CLI and
|
|
86
93
|
API keys cannot turn personal permission on or off. Open the schedule in the browser to
|
package/dist/index.js
CHANGED
|
@@ -7631,6 +7631,21 @@ function printIssueLinks(links) {
|
|
|
7631
7631
|
table(linkRows(links.duplicated_by));
|
|
7632
7632
|
}
|
|
7633
7633
|
}
|
|
7634
|
+
var MOVE_REVISION_HELP = `
|
|
7635
|
+
Every state change advances the issue's decision revision by one (\`tines
|
|
7636
|
+
issues show\` prints it), so leaving a state and returning to it is a different
|
|
7637
|
+
revision. Pass --expect-revision <n> to have the move refused with
|
|
7638
|
+
decision_refresh_required \u2014 nothing written \u2014 when the issue is no longer on
|
|
7639
|
+
the state visit you read. Without it, only a change that commits during this
|
|
7640
|
+
command is caught.
|
|
7641
|
+
`;
|
|
7642
|
+
function parseDecisionRevisionOption(value) {
|
|
7643
|
+
const result = Number(value);
|
|
7644
|
+
if (!/^(0|[1-9]\d*)$/.test(value) || !Number.isSafeInteger(result)) {
|
|
7645
|
+
throw new Error("expect-revision must be a non-negative integer");
|
|
7646
|
+
}
|
|
7647
|
+
return result;
|
|
7648
|
+
}
|
|
7634
7649
|
function printIssueDetail(issue) {
|
|
7635
7650
|
const shared = issue;
|
|
7636
7651
|
if (shared.mode === "member") {
|
|
@@ -7680,6 +7695,8 @@ ${comment.body}`
|
|
|
7680
7695
|
`own state: ${issue.state.name} (${issue.state.category}) \u2014 dormant while this is a duplicate`
|
|
7681
7696
|
);
|
|
7682
7697
|
}
|
|
7698
|
+
if (issue.decision_revision !== void 0)
|
|
7699
|
+
console.log(`decision revision: ${issue.decision_revision}`);
|
|
7683
7700
|
if (issue.project_archived_at !== null) {
|
|
7684
7701
|
console.log(
|
|
7685
7702
|
`project archived: ${timestamp(issue.project_archived_at)} \u2014 this issue is read-only`
|
|
@@ -7984,7 +8001,11 @@ function register3(program3) {
|
|
|
7984
8001
|
}
|
|
7985
8002
|
);
|
|
7986
8003
|
withCommon(
|
|
7987
|
-
issues.command("move <ref> <action>").description("Take a current transition (members: no permission change)")
|
|
8004
|
+
issues.command("move <ref> <action>").description("Take a current transition (members: no permission change)").option(
|
|
8005
|
+
"--expect-revision <n>",
|
|
8006
|
+
"refuse the move unless the issue is still at this decision revision (see `tines issues show`)",
|
|
8007
|
+
parseDecisionRevisionOption
|
|
8008
|
+
).addHelpText("after", MOVE_REVISION_HELP)
|
|
7988
8009
|
).action(async (ref, action2, opts) => {
|
|
7989
8010
|
const api = client(opts);
|
|
7990
8011
|
const issue = await resolveIssue(api, ref);
|
|
@@ -8026,7 +8047,30 @@ function register3(program3) {
|
|
|
8026
8047
|
} : { transition_id: transition.transition_id };
|
|
8027
8048
|
}
|
|
8028
8049
|
}
|
|
8029
|
-
|
|
8050
|
+
if (opts.expectRevision !== void 0) {
|
|
8051
|
+
if (request.transition_id === void 0) {
|
|
8052
|
+
const transition = issue.allowed_transitions.find(
|
|
8053
|
+
(candidate) => candidate.name.toLowerCase() === action2.toLowerCase()
|
|
8054
|
+
);
|
|
8055
|
+
if (!transition)
|
|
8056
|
+
throw new Error(`No current transition named "${action2}"; refresh the issue`);
|
|
8057
|
+
request = { transition_id: transition.transition_id };
|
|
8058
|
+
}
|
|
8059
|
+
request = {
|
|
8060
|
+
...request,
|
|
8061
|
+
expected_state_id: issue.state.id,
|
|
8062
|
+
expected_decision_revision: opts.expectRevision
|
|
8063
|
+
};
|
|
8064
|
+
}
|
|
8065
|
+
const moved = await api.transitionIssue(issue.id, request).catch((error) => {
|
|
8066
|
+
if (opts.expectRevision === void 0 || !(error instanceof ApiError) || error.code !== "decision_refresh_required")
|
|
8067
|
+
throw error;
|
|
8068
|
+
const current = error.details?.current_decision_revision;
|
|
8069
|
+
die(
|
|
8070
|
+
`${error.message} (${error.code})
|
|
8071
|
+
hint: re-read with \`tines issues show ${ref}\`, then retry with --expect-revision ${typeof current === "number" ? current : "<decision revision>"}`
|
|
8072
|
+
);
|
|
8073
|
+
});
|
|
8030
8074
|
if (opts.json) return printJson(moved);
|
|
8031
8075
|
const movedMember = moved;
|
|
8032
8076
|
console.log(
|
|
@@ -14899,9 +14943,18 @@ function resolveBasePair(lib, pair, stateName) {
|
|
|
14899
14943
|
}
|
|
14900
14944
|
return state.id;
|
|
14901
14945
|
}
|
|
14946
|
+
var WORKFLOW_REVISION_HELP = `
|
|
14947
|
+
Every committed update advances the workflow's revision by one (\`tines
|
|
14948
|
+
workflows show\` prints it). Pass --expect-revision <n>, or "expected_revision"
|
|
14949
|
+
in the JSON body (the flag wins), to have the update refused with
|
|
14950
|
+
workflow_conflict \u2014 nothing written \u2014 when the workflow is no longer at the
|
|
14951
|
+
revision you read. Without it, only a save that commits during this command is
|
|
14952
|
+
caught.
|
|
14953
|
+
`;
|
|
14902
14954
|
function printWorkflowDetail(wf, lib) {
|
|
14903
14955
|
console.log(`${wf.name}${wf.is_system ? " (standard, read-only)" : ""} [${wf.id}]`);
|
|
14904
14956
|
if (wf.description) console.log(wf.description);
|
|
14957
|
+
console.log(`revision: ${wf.revision}`);
|
|
14905
14958
|
console.log("\nstates:");
|
|
14906
14959
|
const byId = new Map(wf.states.map((s) => [s.id, s]));
|
|
14907
14960
|
const rows = wf.states.length === 0 ? [] : formatTable(
|
|
@@ -15012,7 +15065,11 @@ see \`tines workflows create --help\` for the expected shape`
|
|
|
15012
15065
|
}
|
|
15013
15066
|
);
|
|
15014
15067
|
withCommon(
|
|
15015
|
-
workflows.command("edit <id-or-name> [json]").description("Update a workflow from a JSON definition and/or flags").option("-f, --file <path>", 'read the JSON definition from a file ("-" for stdin)').option("-n, --name <name>", "rename the workflow").option("-d, --description <text>", "set the description").option("--initial-state <id-or-name>", "set the initial state").option("--no-prompts", 'allow new states without initial "prompt" instructions').
|
|
15068
|
+
workflows.command("edit <id-or-name> [json]").description("Update a workflow from a JSON definition and/or flags").option("-f, --file <path>", 'read the JSON definition from a file ("-" for stdin)').option("-n, --name <name>", "rename the workflow").option("-d, --description <text>", "set the description").option("--initial-state <id-or-name>", "set the initial state").option("--no-prompts", 'allow new states without initial "prompt" instructions').option(
|
|
15069
|
+
"--expect-revision <n>",
|
|
15070
|
+
"refuse the update unless the workflow is still at this revision (see `tines workflows show`)",
|
|
15071
|
+
(value) => parsePositiveIntegerOption(value, "expect-revision")
|
|
15072
|
+
).addHelpText("after", WORKFLOW_JSON_HELP + WORKFLOW_REVISION_HELP)
|
|
15016
15073
|
).action(
|
|
15017
15074
|
async (ref, inline, opts) => {
|
|
15018
15075
|
const api = client(opts);
|
|
@@ -15024,10 +15081,18 @@ see \`tines workflows create --help\` for the expected shape`
|
|
|
15024
15081
|
if (opts.name !== void 0) body.name = opts.name;
|
|
15025
15082
|
if (opts.description !== void 0) body.description = opts.description;
|
|
15026
15083
|
if (opts.initialState !== void 0) body.initial_state = opts.initialState;
|
|
15027
|
-
if (
|
|
15084
|
+
if (opts.expectRevision !== void 0) body.expected_revision = opts.expectRevision;
|
|
15085
|
+
if (Object.keys(body).every((key) => key === "expected_revision")) {
|
|
15028
15086
|
die("nothing to update: pass JSON and/or --name/--description/--initial-state");
|
|
15029
15087
|
}
|
|
15030
|
-
const updated = await api.updateWorkflow(wf.id, body)
|
|
15088
|
+
const updated = await api.updateWorkflow(wf.id, body).catch((error) => {
|
|
15089
|
+
if (!(error instanceof ApiError) || error.code !== "workflow_conflict") throw error;
|
|
15090
|
+
const current = error.details?.current_revision;
|
|
15091
|
+
die(
|
|
15092
|
+
`${error.message} (${error.code})
|
|
15093
|
+
hint: re-read with \`tines workflows show ${wf.id}\`, then retry with --expect-revision ${typeof current === "number" ? current : "<revision>"}`
|
|
15094
|
+
);
|
|
15095
|
+
});
|
|
15031
15096
|
if (opts.json) return printJson(updated);
|
|
15032
15097
|
console.log(`updated workflow "${updated.name}" (${updated.id})
|
|
15033
15098
|
`);
|